Justin Cormack wrote: > On Sat, Aug 25, 2012 at 11:51 PM, Mike Pall <mike-1208@xxxxxxxxxx> wrote: > > I just eliminated a big on: strtod(). Yay! > > [I can post the test cases, if anyone is interested. Almost all > > strtod() implementations are buggy, as I found out.] > > Please do post the test cases. Only, if you promise NOT to spam the list with the results! :-) Send them to the respective library maintainers if you want. GLIBC has already be taken care of (Florian: this one got a couple more hairy overflow/underflow tests). Oh, and yes, MSVCRT doesn't support any hex float conversions (BTW: the pseudo workaround in Lua 5.2 is broken beyond repair). It's hopeless, anyway (read the URLs, somebody tried to report it already). You need to use the latest LuaJIT git HEAD to pass all tests in 'tonumber' mode (testing the internal implementation I wrote). --Mike
local ffi = require("ffi") local bit = require("bit") ffi.cdef[[ double strtod(const char *, char **); ]] local t = { -- Errors false, "", false, " ", false, "+", false, "z", false, ".", false, ".z", false, "0.z", false, ".0z", false, "0xz", false, "0x.z", false, "0x0.z", false, "0x.0z", false, ".e5", false, ".p4", false, "1.p4", false, "1.p+4", false, "0x1.e+4", false, "infi", false, "nano", false, "+ 1", false, "- 9", -- Spacing 0x3ff0000000000000ULL, " \t\n\v\f\r 1", -- inf/nan 0x7ff0000000000000ULL, "iNF", 0xfff0000000000000ULL, "-Inf", 0x7ff0000000000000ULL, "+iNfInItY", 0xfff0000000000000ULL, "-INFINITY", 0xfff8000000000000ULL, "naN", 0xfff8000000000000ULL, "+NaN", 0xfff8000000000000ULL, "-nAn", -- Smallest/largest numbers 0x0000000000000000ULL, "0e1000", 0x0000000000000000ULL, "0e-1000", 0x0000000000000000ULL, "0x0p2000", 0x0000000000000000ULL, "0x0p-2000", 0x7ff0000000000000ULL, "1e1000", 0x0000000000000000ULL, "1e-1000", 0xfff0000000000000ULL, "-1e1000", 0x7ff0000000000000ULL, "0x1p2000", 0x0000000000000000ULL, "0x1p-2000", 0xfff0000000000000ULL, "-0x1p2000", 0x0010000000000000ULL, "2.2250738585072014e-308", 0x7fefffffffffffffULL, "1.7976931348623158e+308", 0x8000b8157268fdafULL, "-1e-309", 0x000ac941b426dd3bULL, "1.5e-308", 0x000ac941b426dd3bULL, "0x0.ac941b426dd3b7p-1022", 0x0000000000000001ULL, "4.9406564584124654e-324", 0x000f9c7573d7fe52ULL, "2.171e-308", 0x241d21ecf36d4a22ULL, "1.0020284025808569e-134", 0x0000000000000001ULL, "0x1p-1074", 0x0000000000000000ULL, "0x1p-1075", 0x0000000000000000ULL, "0x1p-1076", 0x0000000000000000ULL, "0x0.ffffffffffffffffffffffffffp-1075", 0x0000000000000000ULL, "0x1.00000000000000000000000000p-1075", 0x0000000000000001ULL, "0x1.00000000000000000000000001p-1075", 0x7fe0000000000000ULL, "0x1p1023", 0x7ff0000000000000ULL, "0x1p1024", 0x7ff0000000000000ULL, "0x1p1025", 0x7ff0000000000000ULL, "0x3p1023", 0x7ff0000000000000ULL, "0x3.ffffffffffffecp1023", 0xfff0000000000000ULL, "-0xf7dcba98765432p969", 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000000p1023", 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000001p1023", 0x7fefffffffffffffULL, "0x1.fffffffffffff7ffffffffffffp1023", 0x7ff0000000000000ULL, "0x1.fffffffffffff8000000000000p1023", 0x7fefffffffffffffULL, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0", 0x7fefffffffffffffULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.999", 0x7ff0000000000000ULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792.0", 0x3ff0000000000000ULL, "0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000p-1028", -- Old GLIBC bug 0x4370000000000000ULL, "0x100000000000008p0", -- http://www.exploringbinary.com/15-digit-quick-and-dirty-conversions-dont-round-trip/ 0x04409cf3929ffbc3ULL, "3.409452297963e-288", 0x7fe02b4782a6c378ULL, "9.08344e+307", 0x6e05e258a3929ee5ULL, "9.88819e+221", -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/ 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875", 0x42c0000000000002ULL, "3.518437208883201171875e13", 0x404f44abd5aa7ca4ULL, "62.5364939768271845828", 0x3e0bd5cbaef0fd0cULL, "8.10109172351e-10", 0x3ff8000000000000ULL, "1.50000000000000011102230246251565404236316680908203125", 0x433fffffffffffffULL, "9007199254740991.4999999999999999999999999999999995", 0x7ecd2e77eb6e3fadULL, "6.253649397682718e+302", 0x7ecd2e77eb6e3fadULL, "6.2536493976827180e+302", -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/ 0x43405e6cec57761aULL, "9214843084008499", 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875", 0x44997a3c7271b021ULL, "30078505129381147446200", 0x4458180d5bad2e3eULL, "1777820000000000000001", 0x3fe0000000000002ULL, "0.500000000000000166547006220929549868969843373633921146392822265625", 0x3fe0000000000002ULL, "0.50000000000000016656055874808561867439493653364479541778564453125", 0x3fd92bb352c4623aULL, "0.3932922657273", -- http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ 0x0010000000000000ULL, "2.2250738585072012e-308", -- http://www.exploringbinary.com/incorrectly-rounded-subnormal-conversions-in-java/ 0x0000000008000000ULL, "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125e-316", 0x0000000000010000ULL, "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875e-319", 0x0000800000000100ULL, "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125e-310", 0x0000000000010800ULL, "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875e-319", } local function tohex64(x) return bit.tohex(tonumber(x/2LL^32))..bit.tohex(tonumber(x%2LL^32)) end local conv if arg and arg[1] == "tonumber" then conv = tonumber elseif arg and arg[1] == "strtod" then local e = ffi.new("char *[1]") function conv(s) local d = ffi.C.strtod(s, e) return (e[0][0] == 0 and #s ~= 0) and d or nil end else io.stderr:write[[ String to number conversion tests. Specify which implementation to test: tonumber internal implementation strtod strtod() C library call Note: Failures for NaN tests are expected for strtod(), since there's no requirement to return the platform-specific canonical NaN. ]] os.exit(1) end local u = ffi.new("union { double d; uint64_t x; }") for i=1,#t,2 do local y, s = t[i], t[i+1] local d = conv(s) local ok if d == nil then ok = (y == false) else u.d = d ffi.copy(u, u, 8) -- force to memory ok = (y == u.x) end if not ok then io.write('FAIL: "', s, '"\n GOT: ', d and tohex64(u.x) or 'nil', ' OK: ', y and tohex64(y) or 'nil', '\n\n') end end