Re: Strange performance behaviour

  • From: Mike Pall <mike-1208@xxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Mon, 27 Aug 2012 15:48:12 +0200

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

Other related posts: