|
22 | 22 | end |
23 | 23 | end |
24 | 24 |
|
| 25 | + |
| 26 | +-- maximum exponent for a floating-point number |
| 27 | +local maxexp = 0 |
| 28 | +do |
| 29 | + local p = 2.0 |
| 30 | + while p < math.huge do |
| 31 | + maxexp = maxexp + 1 |
| 32 | + p = p + p |
| 33 | + end |
| 34 | +end |
| 35 | + |
| 36 | + |
25 | 37 | local function isNaN (x) |
26 | 38 | return (x ~= x) |
27 | 39 | end |
|
34 | 46 | local x = 2.0^floatbits |
35 | 47 | assert(x > x - 1.0 and x == x + 1.0) |
36 | 48 |
|
37 | | - print(string.format("%d-bit integers, %d-bit (mantissa) floats", |
38 | | - intbits, floatbits)) |
| 49 | + local msg = " %d-bit integers, %d-bit*2^%d floats" |
| 50 | + print(string.format(msg, intbits, floatbits, maxexp)) |
39 | 51 | end |
40 | 52 |
|
41 | 53 | assert(math.type(0) == "integer" and math.type(0.0) == "float" |
|
803 | 815 | end |
804 | 816 |
|
805 | 817 |
|
806 | | -print("testing 'math.random'") |
| 818 | +-- |
| 819 | +-- [[================================================================== |
| 820 | + print("testing 'math.random'") |
| 821 | +-- -=================================================================== |
| 822 | +-- |
807 | 823 |
|
808 | 824 | local random, max, min = math.random, math.max, math.min |
809 | 825 |
|
@@ -1019,6 +1035,90 @@ assert(not pcall(random, minint + 1, minint)) |
1019 | 1035 | assert(not pcall(random, maxint, maxint - 1)) |
1020 | 1036 | assert(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 |
| 1048 | +local decdig = math.floor(floatbits * math.log(2, 10)) |
| 1049 | +print(string.format(" %d-digit float numbers with full precision", |
| 1050 | + decdig)) |
| 1051 | +-- number of decimal digits supported by integer precision |
| 1052 | +local Idecdig = math.floor(math.log(maxint, 10)) |
| 1053 | +print(string.format(" %d-digit integer numbers with full precision", |
| 1054 | + Idecdig)) |
| 1055 | + |
| 1056 | +do |
| 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 | + |
| 1120 | +end |
| 1121 | +-- ]]================================================================== |
1022 | 1122 |
|
1023 | 1123 |
|
1024 | 1124 | print('OK') |
0 commit comments