Floats formatted with "correct" precision
Conversion float->string ensures that, for any float f, tonumber(tostring(f)) == f, but still avoiding noise like 1.1 converting to "1.1000000000000001".
This commit is contained in:
106
testes/math.lua
106
testes/math.lua
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user