|
@@ -22,6 +22,18 @@ do
|
|
|
end
|
|
|
end
|
|
|
|
|
|
+
|
|
|
+-- maximum exponent for a floating-point number
|
|
|
+local maxexp = 0
|
|
|
+do
|
|
|
+ local p = 2.0
|
|
|
+ while p < math.huge do
|
|
|
+ maxexp = maxexp + 1
|
|
|
+ p = p + p
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
local function isNaN (x)
|
|
|
return (x ~= x)
|
|
|
end
|
|
@@ -34,8 +46,8 @@ do
|
|
|
local x = 2.0^floatbits
|
|
|
assert(x > x - 1.0 and x == x + 1.0)
|
|
|
|
|
|
- print(string.format("%d-bit integers, %d-bit (mantissa) floats",
|
|
|
- intbits, floatbits))
|
|
|
+ local msg = " %d-bit integers, %d-bit*2^%d floats"
|
|
|
+ print(string.format(msg, intbits, floatbits, maxexp))
|
|
|
end
|
|
|
|
|
|
assert(math.type(0) == "integer" and math.type(0.0) == "float"
|
|
@@ -803,7 +815,11 @@ do
|
|
|
end
|
|
|
|
|
|
|
|
|
-print("testing 'math.random'")
|
|
|
+--
|
|
|
+-- [[==================================================================
|
|
|
+ print("testing 'math.random'")
|
|
|
+-- -===================================================================
|
|
|
+--
|
|
|
|
|
|
local random, max, min = math.random, math.max, math.min
|
|
|
|
|
@@ -1019,6 +1035,90 @@ assert(not pcall(random, minint + 1, minint))
|
|
|
assert(not pcall(random, maxint, maxint - 1))
|
|
|
assert(not pcall(random, maxint, minint))
|
|
|
|
|
|
+-- ]]==================================================================
|
|
|
+
|
|
|
+
|
|
|
+--
|
|
|
+-- [[==================================================================
|
|
|
+ print("testing precision of 'tostring'")
|
|
|
+-- -===================================================================
|
|
|
+--
|
|
|
+
|
|
|
+-- number of decimal digits supported by float precision
|
|
|
+local decdig = math.floor(floatbits * math.log(2, 10))
|
|
|
+print(string.format(" %d-digit float numbers with full precision",
|
|
|
+ decdig))
|
|
|
+-- number of decimal digits supported by integer precision
|
|
|
+local Idecdig = math.floor(math.log(maxint, 10))
|
|
|
+print(string.format(" %d-digit integer numbers with full precision",
|
|
|
+ Idecdig))
|
|
|
+
|
|
|
+do
|
|
|
+ -- Any number should print so that reading it back gives itself:
|
|
|
+ -- tonumber(tostring(x)) == x
|
|
|
+
|
|
|
+ -- Mersenne fractions
|
|
|
+ local p = 1.0
|
|
|
+ for i = 1, maxexp do
|
|
|
+ p = p + p
|
|
|
+ local x = 1 / (p - 1)
|
|
|
+ assert(x == tonumber(tostring(x)))
|
|
|
+ end
|
|
|
+
|
|
|
+ -- some random numbers in [0,1)
|
|
|
+ for i = 1, 100 do
|
|
|
+ local x = math.random()
|
|
|
+ assert(x == tonumber(tostring(x)))
|
|
|
+ end
|
|
|
+
|
|
|
+ -- different numbers shold print differently.
|
|
|
+ -- check pairs of floats with minimum detectable difference
|
|
|
+ local p = floatbits - 1
|
|
|
+ for i = 1, maxexp - 1 do
|
|
|
+ for _, i in ipairs{-i, i} do
|
|
|
+ local x = 2^i
|
|
|
+ local diff = 2^(i - p) -- least significant bit for 'x'
|
|
|
+ local y = x + diff
|
|
|
+ local fy = tostring(y)
|
|
|
+ assert(x ~= y and tostring(x) ~= fy)
|
|
|
+ assert(tonumber(fy) == y)
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ -- "reasonable" numerals should be printed like themselves
|
|
|
+
|
|
|
+ -- create random float numerals with 5 digits, with a decimal point
|
|
|
+ -- inserted in all places. (With more than 5, things like "0.00001"
|
|
|
+ -- reformats like "1e-5".)
|
|
|
+ for i = 1, 1000 do
|
|
|
+ -- random numeral with 5 digits
|
|
|
+ local x = string.format("%.5d", math.random(0, 99999))
|
|
|
+ for i = 2, #x do
|
|
|
+ -- insert decimal point at position 'i'
|
|
|
+ local y = string.sub(x, 1, i - 1) .. "." .. string.sub(x, i, -1)
|
|
|
+ y = string.gsub(y, "^0*(%d.-%d)0*$", "%1") -- trim extra zeros
|
|
|
+ assert(y == tostring(tonumber(y)))
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ -- all-random floats
|
|
|
+ local Fsz = string.packsize("n") -- size of floats in bytes
|
|
|
+
|
|
|
+ for i = 1, 400 do
|
|
|
+ local s = string.pack("j", math.random(0)) -- a random string of bits
|
|
|
+ while #s < Fsz do -- make 's' long enough
|
|
|
+ s = s .. string.pack("j", math.random(0))
|
|
|
+ end
|
|
|
+ local n = string.unpack("n", s) -- read 's' as a float
|
|
|
+ s = tostring(n)
|
|
|
+ if string.find(s, "^%-?%d") then -- avoid NaN, inf, -inf
|
|
|
+ assert(tonumber(s) == n)
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+end
|
|
|
+-- ]]==================================================================
|
|
|
|
|
|
|
|
|
print('OK')
|