private void ParseDecimalNumber(ref TokenInfo info) { _builder.Clear(); SkipDecimalDigits(_builder); if (_reader.IsNext('.')) { _builder.Append(_reader.Read() !.Value); SkipDecimalDigits(_builder); } if (CharUtils.AsciiLowerCase(_reader.Peek().GetValueOrDefault()) == 'e') { _builder.Append(_reader.Read() !.Value); if (_reader.IsNext('+') || _reader.IsNext('-')) { _builder.Append(_reader.Read() !.Value); } SkipDecimalDigits(_builder); } info.Text = GetText(intern: true); if (!Options.SyntaxOptions.AcceptUnderscoreInNumberLiterals && info.Text.IndexOf('_') >= 0) { AddError(ErrorCode.ERR_UnderscoreInNumericLiteralNotSupportedInVersion); } if (!RealParser.TryParseDouble(Intern(_builder), out var result)) { AddError(ErrorCode.ERR_DoubleOverflow); } info.DoubleValue = result; }
public void TestRandomFloatStrings() { var start = DateTime.UtcNow; // compare our atof on random strings against C's strtof Parallel.For( 0, 150, part => { Random r = new Random(start.GetHashCode() + part); var b = new StringBuilder(); for (int i = 0; i < 100000; i++) { b.Clear(); int beforeCount = r.Next(3); int afterCount = r.Next(1 + part % 50); int exp = r.Next(-50, 40); if (beforeCount == 0) { b.Append('0'); } for (int j = 0; j < beforeCount; j++) { b.Append((char)('0' + r.Next(10))); } b.Append('.'); for (int j = 0; j < afterCount; j++) { b.Append((char)('0' + r.Next(10))); } b.Append('e'); if (exp >= 0 && r.Next(2) == 0) { b.Append('+'); } b.Append(exp); var s = b.ToString(); float d1; d1 = CLibraryShim.RealConversions.atof(s); float d2; if (!RealParser.TryParseFloat(s, out d2)) { d2 = 1.0f / 0.0f; } Assert.AreEqual( d1, d2, 0.0, $"{s} differ\n RealParser=>{d2:G17}\n atof=>{d1:G17}\n" ); } } ); }
private static void CheckOneFloat(string s, float expected) { float actual; if (!RealParser.TryParseFloat(s, out actual)) { actual = 1.0f / 0.0f; } if (!actual.Equals(expected)) { throw new Exception($@"Error for float input ""{s}"" expected {InvariantToString(expected)} actual {InvariantToString(actual)}"); } }
private static void CheckOneDouble(string s, double expected) { double actual; if (!RealParser.TryParseDouble(s, out actual)) { actual = 1.0 / 0.0; } if (!actual.Equals(expected)) { throw new Exception($@" Error for double input ""{s}"" expected {InvariantToString(expected)} actual {InvariantToString(actual)}"); } }
private void Awake() { if (_rp != null && _rp != this) { Destroy(this.gameObject); } else { _rp = this; } //blank key to give access to any dialoge that has no key inv.Add(000, ""); pickUp = GetComponent <AudioSource>(); }
static void CheckOneFloat(string s, float expected) { float actual; if (!RealParser.TryParseFloat(s, out actual)) { actual = 1.0f / 0.0f; } if (!actual.Equals(expected)) { #if DEBUG throw new AssertFailureException($@"Error for float input ""{s}"" expected {expected:G17} actual {actual:G17}"); #else throw new Exception($@"Error for float input ""{s}"" expected {expected:G17} actual {actual:G17}"); #endif } }
static void CheckOneDouble(string s, double expected) { double actual; if (!RealParser.TryParseDouble(s, out actual)) { actual = 1.0 / 0.0; } if (!actual.Equals(expected)) { #if DEBUG throw new AssertFailureException($@" Error for double input ""{s}"" expected {expected:G17} actual {actual:G17}"); #else throw new Exception($@" Error for double input ""{s}"" expected {expected:G17} actual {actual:G17}"); #endif } }
public static void TestSpecificDoubles() { CheckOneDouble("0.0", 0x0000000000000000ul); // Verify the smallest denormals: for (ulong i = 0x0000000000000001ul; i != 0x0000000000000100ul; ++i) { TestRoundTripDouble(i); } // Verify the largest denormals and the smallest normals: for (ulong i = 0x000fffffffffff00ul; i != 0x0010000000000100ul; ++i) { TestRoundTripDouble(i); } // Verify the largest normals: for (ulong i = 0x7fefffffffffff00ul; i != 0x7ff0000000000000ul; ++i) { TestRoundTripDouble(i); } // Verify all representable powers of two and nearby values: for (int pow = -1022; pow <= 1023; pow++) { ulong twoToThePow = ((ulong)(pow + 1023)) << 52; TestRoundTripDouble(twoToThePow); TestRoundTripDouble(twoToThePow + 1); TestRoundTripDouble(twoToThePow - 1); } // Verify all representable powers of ten and nearby values: for (int pow = -323; pow <= 308; pow++) { var s = $"1.0e{pow}"; double value; RealParser.TryParseDouble(s, out value); var tenToThePow = (ulong)BitConverter.DoubleToInt64Bits(value); CheckOneDouble(s, value); TestRoundTripDouble(tenToThePow + 1); TestRoundTripDouble(tenToThePow - 1); } // Verify a few large integer values: TestRoundTripDouble((double)long.MaxValue); TestRoundTripDouble((double)ulong.MaxValue); // Verify small and large exactly representable integers: CheckOneDouble("1", 0x3ff0000000000000); CheckOneDouble("2", 0x4000000000000000); CheckOneDouble("3", 0x4008000000000000); CheckOneDouble("4", 0x4010000000000000); CheckOneDouble("5", 0x4014000000000000); CheckOneDouble("6", 0x4018000000000000); CheckOneDouble("7", 0x401C000000000000); CheckOneDouble("8", 0x4020000000000000); CheckOneDouble("9007199254740984", 0x433ffffffffffff8); CheckOneDouble("9007199254740985", 0x433ffffffffffff9); CheckOneDouble("9007199254740986", 0x433ffffffffffffa); CheckOneDouble("9007199254740987", 0x433ffffffffffffb); CheckOneDouble("9007199254740988", 0x433ffffffffffffc); CheckOneDouble("9007199254740989", 0x433ffffffffffffd); CheckOneDouble("9007199254740990", 0x433ffffffffffffe); CheckOneDouble("9007199254740991", 0x433fffffffffffff); // 2^53 - 1 // Verify the smallest and largest denormal values: CheckOneDouble("5.0e-324", 0x0000000000000001); CheckOneDouble("1.0e-323", 0x0000000000000002); CheckOneDouble("1.5e-323", 0x0000000000000003); CheckOneDouble("2.0e-323", 0x0000000000000004); CheckOneDouble("2.5e-323", 0x0000000000000005); CheckOneDouble("3.0e-323", 0x0000000000000006); CheckOneDouble("3.5e-323", 0x0000000000000007); CheckOneDouble("4.0e-323", 0x0000000000000008); CheckOneDouble("4.5e-323", 0x0000000000000009); CheckOneDouble("5.0e-323", 0x000000000000000a); CheckOneDouble("5.5e-323", 0x000000000000000b); CheckOneDouble("6.0e-323", 0x000000000000000c); CheckOneDouble("6.5e-323", 0x000000000000000d); CheckOneDouble("7.0e-323", 0x000000000000000e); CheckOneDouble("7.5e-323", 0x000000000000000f); CheckOneDouble("2.2250738585071935e-308", 0x000ffffffffffff0); CheckOneDouble("2.2250738585071940e-308", 0x000ffffffffffff1); CheckOneDouble("2.2250738585071945e-308", 0x000ffffffffffff2); CheckOneDouble("2.2250738585071950e-308", 0x000ffffffffffff3); CheckOneDouble("2.2250738585071955e-308", 0x000ffffffffffff4); CheckOneDouble("2.2250738585071960e-308", 0x000ffffffffffff5); CheckOneDouble("2.2250738585071964e-308", 0x000ffffffffffff6); CheckOneDouble("2.2250738585071970e-308", 0x000ffffffffffff7); CheckOneDouble("2.2250738585071974e-308", 0x000ffffffffffff8); CheckOneDouble("2.2250738585071980e-308", 0x000ffffffffffff9); CheckOneDouble("2.2250738585071984e-308", 0x000ffffffffffffa); CheckOneDouble("2.2250738585071990e-308", 0x000ffffffffffffb); CheckOneDouble("2.2250738585071994e-308", 0x000ffffffffffffc); CheckOneDouble("2.2250738585072000e-308", 0x000ffffffffffffd); CheckOneDouble("2.2250738585072004e-308", 0x000ffffffffffffe); CheckOneDouble("2.2250738585072010e-308", 0x000fffffffffffff); // Test cases from Rick Regan's article, "Incorrectly Rounded Conversions in Visual C++": // // http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/ // // Example 1: CheckOneDouble( "9214843084008499", 0x43405e6cec57761a); // Example 2: CheckOneDouble( "0.500000000000000166533453693773481063544750213623046875", 0x3fe0000000000002); // Example 3 (2^-1 + 2^-53 + 2^-54): CheckOneDouble( "30078505129381147446200", 0x44997a3c7271b021); // Example 4: CheckOneDouble( "1777820000000000000001", 0x4458180d5bad2e3e); // Example 5 (2^-1 + 2^-53 + 2^-54 + 2^-66): CheckOneDouble( "0.500000000000000166547006220929549868969843373633921146392822265625", 0x3fe0000000000002); // Example 6 (2^-1 + 2^-53 + 2^-54 + 2^-65): CheckOneDouble( "0.50000000000000016656055874808561867439493653364479541778564453125", 0x3fe0000000000002); // Example 7: CheckOneDouble( "0.3932922657273", 0x3fd92bb352c4623a ); // The following test cases are taken from other articles on Rick Regan's // Exploring Binary blog. These are conversions that other implementations // were found to perform incorrectly. // http://www.exploringbinary.com/nondeterministic-floating-point-conversions-in-java/ // http://www.exploringbinary.com/incorrectly-rounded-subnormal-conversions-in-java/ // Example 1 (2^-1047 + 2^-1075, half-ulp above a power of two): CheckOneDouble( "6.6312368714697582767853966302759672433990999473553031442499717587" + "362866301392654396180682007880487441059604205526018528897150063763" + "256665955396033303618005191075917832333584923372080578494993608994" + "251286407188566165030934449228547591599881603044399098682919739314" + "266256986631577498362522745234853124423586512070512924530832781161" + "439325697279187097860044978723221938561502254152119972830784963194" + "121246401117772161481107528151017752957198119743384519360959074196" + "224175384736794951486324803914359317679811223967034438033355297560" + "033532098300718322306892013830155987921841729099279241763393155074" + "022348361207309147831684007154624400538175927027662135590421159867" + "638194826541287705957668068727833491469671712939495988506756821156" + "96218943412532098591327667236328125E-316", 0x0000000008000000); // Example 2 (2^-1058 - 2^-1075, half-ulp below a power of two): CheckOneDouble( "3.2378839133029012895883524125015321748630376694231080599012970495" + "523019706706765657868357425877995578606157765598382834355143910841" + "531692526891905643964595773946180389283653051434639551003566966656" + "292020173313440317300443693602052583458034314716600326995807313009" + "548483639755486900107515300188817581841745696521731104736960227499" + "346384253806233697747365600089974040609674980283891918789639685754" + "392222064169814626901133425240027243859416510512935526014211553334" + "302252372915238433223313261384314778235911424088000307751706259156" + "707286570031519536642607698224949379518458015308952384398197084033" + "899378732414634842056080000272705311068273879077914449185347715987" + "501628125488627684932015189916680282517302999531439241685457086639" + "13273994694463908672332763671875E-319", 0x0000000000010000); // Example 3 (2^-1027 + 2^-1066 + 2^-1075, half-ulp above a non-power of two): CheckOneDouble( "6.9533558078476771059728052155218916902221198171459507544162056079" + "800301315496366888061157263994418800653863998640286912755395394146" + "528315847956685600829998895513577849614468960421131982842131079351" + "102171626549398024160346762138294097205837595404767869364138165416" + "212878432484332023692099166122496760055730227032447997146221165421" + "888377703760223711720795591258533828013962195524188394697705149041" + "926576270603193728475623010741404426602378441141744972109554498963" + "891803958271916028866544881824524095839813894427833770015054620157" + "450178487545746683421617594966617660200287528887833870748507731929" + "971029979366198762266880963149896457660004790090837317365857503352" + "620998601508967187744019647968271662832256419920407478943826987518" + "09812609536720628966577351093292236328125E-310", 0x0000800000000100 ); // Example 4 (2^-1058 + 2^-1063 + 2^-1075, half-ulp below a non-power of two): CheckOneDouble( "3.3390685575711885818357137012809439119234019169985217716556569973" + "284403145596153181688491490746626090999981130094655664268081703784" + "340657229916596426194677060348844249897410807907667784563321682004" + "646515939958173717821250106683466529959122339932545844611258684816" + "333436749050742710644097630907080178565840197768788124253120088123" + "262603630354748115322368533599053346255754042160606228586332807443" + "018924703005556787346899784768703698535494132771566221702458461669" + "916553215355296238706468887866375289955928004361779017462862722733" + "744717014529914330472578638646014242520247915673681950560773208853" + "293843223323915646452641434007986196650406080775491621739636492640" + "497383622906068758834568265867109610417379088720358034812416003767" + "05491726170293986797332763671875E-319", 0x0000000000010800 ); // http://www.exploringbinary.com/gays-strtod-returns-zero-for-inputs-just-above-2-1075/ // A number between 2^-2074 and 2^-1075, just slightly larger than 2^-1075. // It has bit 1075 set (the denormal rounding bit), followed by 2506 zeroes, // followed by one bits. It should round up to 2^-1074. CheckOneDouble( "2.470328229206232720882843964341106861825299013071623822127928412503" + "37753635104375932649918180817996189898282347722858865463328355177969" + "89819938739800539093906315035659515570226392290858392449105184435931" + "80284993653615250031937045767824921936562366986365848075700158576926" + "99037063119282795585513329278343384093519780155312465972635795746227" + "66465272827220056374006485499977096599470454020828166226237857393450" + "73633900796776193057750674017632467360096895134053553745851666113422" + "37666786041621596804619144672918403005300575308490487653917113865916" + "46239524912623653881879636239373280423891018672348497668235089863388" + "58792562830275599565752445550725518931369083625477918694866799496832" + "40497058210285131854513962138377228261454376934125320985913276672363" + "28125001e-324", 0x0000000000000001); }
#pragma warning restore IDE0079 // Remove unnecessary suppression private void ParseDecimalNumber(ref TokenInfo info) { _builder.Clear(); var isFloat = false; ConsumeDecimalDigits(_builder); if (TextWindow.PeekChar() == '.') { TextWindow.AdvanceChar(); isFloat = true; _builder.Append('.'); ConsumeDecimalDigits(_builder); } if (CharUtils.AsciiLowerCase(TextWindow.PeekChar()) == 'e') { TextWindow.AdvanceChar(); isFloat = true; _builder.Append('e'); if (TextWindow.PeekChar() is '+' or '-') { _builder.Append(TextWindow.NextChar()); } ConsumeDecimalDigits(_builder); } var(isUnsignedLong, isSignedLong, isComplex) = (false, false, false); if (TextWindow.AdvanceIfMatches("ull", true)) { if (isFloat) { AddError(ErrorCode.ERR_LuajitSuffixInFloat); } else { isUnsignedLong = true; } } else if (TextWindow.AdvanceIfMatches("ll", true)) { if (isFloat) { AddError(ErrorCode.ERR_LuajitSuffixInFloat); } else { isSignedLong = true; } } else if (TextWindow.AdvanceIfMatches("i", true)) { isComplex = true; } info.Text = TextWindow.GetText(intern: true); if (!_options.SyntaxOptions.AcceptUnderscoreInNumberLiterals && info.Text.IndexOf('_') >= 0) { AddError(ErrorCode.ERR_UnderscoreInNumericLiteralNotSupportedInVersion); } if (!Options.SyntaxOptions.AcceptLuaJITNumberSuffixes && (isUnsignedLong || isSignedLong || isComplex)) { AddError(ErrorCode.ERR_NumberSuffixNotSupportedInVersion); } if (isUnsignedLong) { if (!ulong.TryParse(TextWindow.Intern(_builder), NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { AddError(ErrorCode.ERR_NumericLiteralTooLarge); } info.ValueKind = ValueKind.ULong; info.ULongValue = result; } else if (isSignedLong) { if (!long.TryParse(TextWindow.Intern(_builder), NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { AddError(ErrorCode.ERR_NumericLiteralTooLarge); } info.ValueKind = ValueKind.Long; info.LongValue = result; } else if (isComplex) { if (!RealParser.TryParseDouble(TextWindow.Intern(_builder), out var result)) { AddError(ErrorCode.ERR_DoubleOverflow); } info.ValueKind = ValueKind.Complex; info.ComplexValue = new Complex(0, result); } else if (isFloat || _options.SyntaxOptions.DecimalIntegerFormat == IntegerFormats.NotSupported) { if (!RealParser.TryParseDouble(TextWindow.Intern(_builder), out var result)) { AddError(ErrorCode.ERR_DoubleOverflow); } info.ValueKind = ValueKind.Double; info.DoubleValue = result; } else { if (!long.TryParse(TextWindow.Intern(_builder), NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { AddError(ErrorCode.ERR_NumericLiteralTooLarge); } switch (_options.SyntaxOptions.DecimalIntegerFormat) { case IntegerFormats.Double: info.ValueKind = ValueKind.Double; info.DoubleValue = result; break; case IntegerFormats.Int64: info.ValueKind = ValueKind.Long; info.LongValue = result; break; default: throw ExceptionUtilities.UnexpectedValue(_options.SyntaxOptions.DecimalIntegerFormat); } } }