aboutsummaryrefslogtreecommitdiff
path: root/testes
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-02 15:09:30 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-02 15:09:30 -0300
commit1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a (patch)
tree5162b1f662c4dcb6127ba03866096f70d0c298ab /testes
parent4c6afbcb01d1cae72d829af5301df5f592fa2079 (diff)
downloadlua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.tar.gz
lua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.tar.bz2
lua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.zip
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".
Diffstat (limited to 'testes')
-rw-r--r--testes/math.lua106
1 files changed, 103 insertions, 3 deletions
diff --git a/testes/math.lua b/testes/math.lua
index 0191f7dd..3937b9ce 100644
--- a/testes/math.lua
+++ b/testes/math.lua
@@ -22,6 +22,18 @@ do
22 end 22 end
23end 23end
24 24
25
26-- maximum exponent for a floating-point number
27local maxexp = 0
28do
29 local p = 2.0
30 while p < math.huge do
31 maxexp = maxexp + 1
32 p = p + p
33 end
34end
35
36
25local function isNaN (x) 37local function isNaN (x)
26 return (x ~= x) 38 return (x ~= x)
27end 39end
@@ -34,8 +46,8 @@ do
34 local x = 2.0^floatbits 46 local x = 2.0^floatbits
35 assert(x > x - 1.0 and x == x + 1.0) 47 assert(x > x - 1.0 and x == x + 1.0)
36 48
37 print(string.format("%d-bit integers, %d-bit (mantissa) floats", 49 local msg = " %d-bit integers, %d-bit*2^%d floats"
38 intbits, floatbits)) 50 print(string.format(msg, intbits, floatbits, maxexp))
39end 51end
40 52
41assert(math.type(0) == "integer" and math.type(0.0) == "float" 53assert(math.type(0) == "integer" and math.type(0.0) == "float"
@@ -803,7 +815,11 @@ do
803end 815end
804 816
805 817
806print("testing 'math.random'") 818--
819-- [[==================================================================
820 print("testing 'math.random'")
821-- -===================================================================
822--
807 823
808local random, max, min = math.random, math.max, math.min 824local random, max, min = math.random, math.max, math.min
809 825
@@ -1019,6 +1035,90 @@ assert(not pcall(random, minint + 1, minint))
1019assert(not pcall(random, maxint, maxint - 1)) 1035assert(not pcall(random, maxint, maxint - 1))
1020assert(not pcall(random, maxint, minint)) 1036assert(not pcall(random, maxint, minint))
1021 1037
1038-- ]]==================================================================
1039
1040
1041--
1042-- [[==================================================================
1043 print("testing precision of 'tostring'")
1044-- -===================================================================
1045--
1046
1047-- number of decimal digits supported by float precision
1048local decdig = math.floor(floatbits * math.log(2, 10))
1049print(string.format(" %d-digit float numbers with full precision",
1050 decdig))
1051-- number of decimal digits supported by integer precision
1052local Idecdig = math.floor(math.log(maxint, 10))
1053print(string.format(" %d-digit integer numbers with full precision",
1054 Idecdig))
1055
1056do
1057 -- Any number should print so that reading it back gives itself:
1058 -- tonumber(tostring(x)) == x
1059
1060 -- Mersenne fractions
1061 local p = 1.0
1062 for i = 1, maxexp do
1063 p = p + p
1064 local x = 1 / (p - 1)
1065 assert(x == tonumber(tostring(x)))
1066 end
1067
1068 -- some random numbers in [0,1)
1069 for i = 1, 100 do
1070 local x = math.random()
1071 assert(x == tonumber(tostring(x)))
1072 end
1073
1074 -- different numbers shold print differently.
1075 -- check pairs of floats with minimum detectable difference
1076 local p = floatbits - 1
1077 for i = 1, maxexp - 1 do
1078 for _, i in ipairs{-i, i} do
1079 local x = 2^i
1080 local diff = 2^(i - p) -- least significant bit for 'x'
1081 local y = x + diff
1082 local fy = tostring(y)
1083 assert(x ~= y and tostring(x) ~= fy)
1084 assert(tonumber(fy) == y)
1085 end
1086 end
1087
1088
1089 -- "reasonable" numerals should be printed like themselves
1090
1091 -- create random float numerals with 5 digits, with a decimal point
1092 -- inserted in all places. (With more than 5, things like "0.00001"
1093 -- reformats like "1e-5".)
1094 for i = 1, 1000 do
1095 -- random numeral with 5 digits
1096 local x = string.format("%.5d", math.random(0, 99999))
1097 for i = 2, #x do
1098 -- insert decimal point at position 'i'
1099 local y = string.sub(x, 1, i - 1) .. "." .. string.sub(x, i, -1)
1100 y = string.gsub(y, "^0*(%d.-%d)0*$", "%1") -- trim extra zeros
1101 assert(y == tostring(tonumber(y)))
1102 end
1103 end
1104
1105 -- all-random floats
1106 local Fsz = string.packsize("n") -- size of floats in bytes
1107
1108 for i = 1, 400 do
1109 local s = string.pack("j", math.random(0)) -- a random string of bits
1110 while #s < Fsz do -- make 's' long enough
1111 s = s .. string.pack("j", math.random(0))
1112 end
1113 local n = string.unpack("n", s) -- read 's' as a float
1114 s = tostring(n)
1115 if string.find(s, "^%-?%d") then -- avoid NaN, inf, -inf
1116 assert(tonumber(s) == n)
1117 end
1118 end
1119
1120end
1121-- ]]==================================================================
1022 1122
1023 1123
1024print('OK') 1124print('OK')