As you know, float point has a precision problem, that is a value 1 will be 0.9999999. And lua use == in C to check whether two double numbers equal. So the problem is:
a = 5.6
b = 14 * 0.4
print(a==b) ; => false
But the worse thing is:
a = 1
...
if a < 1 then print("<1") end ; => sometimes a < 1
So how can i avoid this ? I check out lua source code, it seems i can modify luai_numeq/luai_numle) macros in luaconf.h, but is this necessary ?
update
The second example is not really correct. Actually my problem is, I pass a value 1 to c/c++ which use lua_tonumber to get the value, and i store this value in a double variable, and after sometime, I push the value (lua_pushnumber) to lua, and a < 1 happened:
in lua:
my_cfunction(1)
...
in c:
int my_cfunction(lua_State *L) {
double val = lua_tonumber(L, 1);
...
...
lua_pushnumber(L, val);
in lua:
local a = my_cfunction2()
if a < 1 then ... end
As you know, float point has a precision problem, that is a value 1 will be 0.9999999
I don't know that at all. Because it's not true. 1.0 is 1.0. This:
a = 1
if a < 1 then print("<1") end
Will never print "<1". Not unless you actually change a. Even this:
a = 2
a = a - 1
if a < 1 then print("<1") end
Will likewise never hit the print statement.
As long as you are performing integer arithmetic on Lua's numbers, you will end up with integers. No addition, subtraction, or multiplication of integer values will leave you with a non-integer number value.
float point has a precision problem
It doesn't.
A 64 bit double can hold many more integer values precisely than a 32 bit integer.
Related
This code checks that the value a maps uniquely for the values 1 to 100 using the formula (a^x) % 101
local function f(a)
found = {}
bijective = true
for x = 1, 100 do
value = (a^x) % 101
if found[value] then
bijective = false
break
else
found[value] = x
end
end
return bijective
end
However does not produce the expected result.
it maps 2^65 % 101 to 56, which matches the value produced by 2^12 % 101 and I get a false result, however the correct value for 2^65 % 101 is 57 and 2 actually should produce all unique values resulting in a true result.
The error described above is specifically on Lua 5.1, is this just a quirk of Lua's number typing? Is there a way to make this function work correctly in 5.1?
The error described above is specifically on Lua 5.1, is this just a quirk of Lua's number typing? Is there a way to make this function work correctly in 5.1?
First of all, this is not an issue with Lua's number typing since 2^65, being a (rather small) power of two, can be represented exactly by the double precision since it uses an exponent-mantissa representation. The mantissa can simply be set to all zeroes (leading one is implicit) and the exponent must be set to 65 (+ offset).
I tried this on different Lua versions and PUC Lua 5.1 & 5.2 as well as LuaJIT have the issue; Lua 5.3 (and presumably later versions as well) are fine. Interestingly, using math.fmod(2^65, 101) returns the correct result on the older Lua versions but 2^65 % 101 does not (it returns 0 instead).
This surprised me so I dug in the Lua 5.1 sources. This is the implementation of math.fmod:
#include <math.h>
...
static int math_fmod (lua_State *L) {
lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
return 1;
}
this also is the only place where fmod from math.h appears to be used. The % operator on the other hand is implemented as documented in the reference manual:
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
in src/luaconf.h. You could trivially redefine it as fmod(a,b) to fix your issue. In fact Lua 5.4 does something similar and even provides an elaborate explanation in its sources!
/*
** modulo: defined as 'a - floor(a/b)*b'; the direct computation
** using this definition has several problems with rounding errors,
** so it is better to use 'fmod'. 'fmod' gives the result of
** 'a - trunc(a/b)*b', and therefore must be corrected when
** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
** non-integer negative result: non-integer result is equivalent to
** a non-zero remainder 'm'; negative result is equivalent to 'a' and
** 'b' with different signs, or 'm' and 'b' with different signs
** (as the result 'm' of 'fmod' has the same sign of 'a').
*/
#if !defined(luai_nummod)
#define luai_nummod(L,a,b,m) \
{ (void)L; (m) = l_mathop(fmod)(a,b); \
if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); }
#endif
Is there a way to make this function work correctly in 5.1?
Yes: The easy way is to use fmod. This may work for these particular numbers since they still fit in doubles due to the base being 2 and the exponent being moderately small, but it won't work in the general case. The better approach is to leverage modular arithmetics to keep your intermediate results small, never storing numbers significantly larger than 101^2 since (a * b) % c == (a % c) * (b % c).
local function f(a)
found = {}
bijective = true
local value = 1
for _ = 1, 100 do
value = (value * a) % 101 -- a^x % 101
if found[value] then
bijective = false
break
else
found[value] = x
end
end
return bijective
end
I have trouble with integer division in Dart as it gives me error: 'Breaking on exception: type 'double' is not a subtype of type 'int' of 'c'.'
Here's the following code:
int a = 500;
int b = 250;
int c;
c = a / b; // <-- Gives warning in Dart Editor, and throws an error in runtime.
As you see, I was expecting that the result should be 2, or say, even if division of 'a' or 'b' would have a result of a float/double value, it should be converted directly to integer value, instead of throwing error like that.
I have a workaround by using .round()/.ceil()/.floor(), but this won't suffice as in my program, this little operation is critical as it is called thousands of times in one game update (or you can say in requestAnimationFrame).
I have not found any other solution to this yet, any idea? Thanks.
Dart version: 1.0.0_r30798
That is because Dart uses double to represent all numbers in dart2js. You can get interesting results, if you play with that:
Code:
int a = 1;
a is int;
a is double;
Result:
true
true
Actually, it is recommended to use type num when it comes to numbers, unless you have strong reasons to make it int (in for loop, for example). If you want to keep using int, use truncating division like this:
int a = 500;
int b = 250;
int c;
c = a ~/ b;
Otherwise, I would recommend to utilize num type.
Integer division is
c = a ~/ b;
you could also use
c = (a / b).floor();
c = (a / b).ceil();
if you want to define how fractions should be handled.
Short Answer
Use c = a ~/ b.
Long Answer
According to the docs, int are numbers without a decimal point, while double are numbers with a decimal point.
Both double and int are subtypes of num.
When two integers are divided using the / operator, the result is evaluated into a double. And the c variable was initialized as an integer. There are at least two things you can do:
Use c = a ~/ b.
The ~/ operator returns an int.
Use var c;. This creates a dynamic variable that can be assigned to any type, including a double and int and String etc.
Truncating division operator
You can use the truncating division operator ~/ to get an integer result from a division operation:
4 ~/ 2; // 2 (int)
Division operator
The regular division operator / will always return a double value at runtime (see the docs):
for (var i = 4; i == 4; i = 3) {
i / 2; // 2 (double)
}
Runtime versus compile time
You might have noticed that I wrote a loop for the second example (for the regular division operator) instead of 4 / 2.
The reason for this is the following:
When an expression can be evaluated at compile time, it will be simplified at that stage and also be typed accordingly. The compiler would simply convert 4 / 2 to 2 at compile time, which is then obviously an int. The loop prevents the compiler from evaluating the expression.
As long as your division happens at runtime (i.e. with variables that cannot be predicted at compile time), the return types of the / (double) and ~/ (int) operators will be the types you will see for your expressions at runtime.
See this fun example for further reference.
Conclusion
Generally speaking, the regular division operator / always returns a double value and truncate divide can be used to get an int result instead.
Compiler optimization might, however, cause some funky results :)
Which is the best efficient way to round up a number and then truncate it (remove decimal places after rounding up)?
for example if decimal is above 0.5 (that is, 0.6, 0.7, and so on), I want to round up and then truncate (case 1). Otherwise, I would like to truncate (case 2)
for example:
232.98266601563 => after rounding and truncate = 233 (case 1)
232.49445450000 => after rounding and truncate = 232 (case 2)
232.50000000000 => after rounding and truncate = 232 (case 2)
There is no build-in math.round() function in Lua, but you can do the following:
print(math.floor(a+0.5)).
A trick that is useful for rounding at decimal digits other than whole integers is to pass the value through formatted ASCII text, and use the %f format string to specify the rounding desired. For example
mils = tonumber(string.format("%.3f", exact))
will round the arbitrary value in exact to a multiple of 0.001.
A similar result can be had with scaling before and after using one of math.floor() or math.ceil(), but getting the details right according to your expectations surrounding the treatment of edge cases can be tricky. Not that this isn't an issue with string.format(), but a lot of work has gone into making it produce "expected" results.
Rounding to a multiple of something other than a power of ten will still require scaling, and still has all the tricky edge cases. One approach that is simple to express and has stable behavior is to write
function round(exact, quantum)
local quant,frac = math.modf(exact/quantum)
return quantum * (quant + (frac > 0.5 and 1 or 0))
end
and tweak the exact condition on frac (and possibly the sign of exact) to get the edge cases you wanted.
To also support negative numbers, use this:
function round(x)
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
If your Lua uses double precision IEC-559 (aka IEEE-754) floats, as most do, and your numbers are relatively small (the method is guaranteed to work for inputs between -251 and 251), the following efficient code will perform rounding using your FPU's current rounding mode, which is usually round to nearest, ties to even:
local function round(num)
return num + (2^52 + 2^51) - (2^52 + 2^51)
end
(Note that the numbers in parentheses are calculated at compilation time; they don't affect runtime).
For example, when the FPU is set to round to nearest or even, this unit test prints "All tests passed":
local function testnum(num, expected)
if round(num) ~= expected then
error(("Failure rounding %.17g, expected %.17g, actual %.17g")
:format(num+0, expected+0, round(num)+0))
end
end
local function test(num, expected)
testnum(num, expected)
testnum(-num, -expected)
end
test(0, 0)
test(0.2, 0)
test(0.4, 0)
-- Most rounding algorithms you find on the net, including Ola M's answer,
-- fail this one:
test(0.49999999999999994, 0)
-- Ties are rounded to the nearest even number, rather than always up:
test(0.5, 0)
test(0.5000000000000001, 1)
test(1.4999999999999998, 1)
test(1.5, 2)
test(2.5, 2)
test(3.5, 4)
test(2^51-0.5, 2^51)
test(2^51-0.75, 2^51-1)
test(2^51-1.25, 2^51-1)
test(2^51-1.5, 2^51-2)
print("All tests passed")
Here's another (less efficient, of course) algorithm that performs the same FPU rounding but works for all numbers:
local function round(num)
local ofs = 2^52
if math.abs(num) > ofs then
return num
end
return num < 0 and num - ofs + ofs or num + ofs - ofs
end
Here's one to round to an arbitrary number of digits (0 if not defined):
function round(x, n)
n = math.pow(10, n or 0)
x = x * n
if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
return x / n
end
For bad rounding (cutting the end off):
function round(number)
return number - (number % 1)
end
Well, if you want, you can expand this for good rounding.
function round(number)
if (number - (number % 0.1)) - (number - (number % 1)) < 0.5 then
number = number - (number % 1)
else
number = (number - (number % 1)) + 1
end
return number
end
print(round(3.1))
print(round(math.pi))
print(round(42))
print(round(4.5))
print(round(4.6))
Expected results:
3, 3, 42, 5, 5
I like the response above by RBerteig: mils = tonumber(string.format("%.3f", exact)).
Expanded it to a function call and added a precision value.
function round(number, precision)
local fmtStr = string.format('%%0.%sf',precision)
number = string.format(fmtStr,number)
return number
end
Should be math.ceil(a-0.5) to correctly handle half-integer numbers
Here is a flexible function to round to different number of places. I tested it with negative numbers, big numbers, small numbers, and all manner of edge cases, and it is useful and reliable:
function Round(num, dp)
--[[
round a number to so-many decimal of places, which can be negative,
e.g. -1 places rounds to 10's,
examples
173.2562 rounded to 0 dps is 173.0
173.2562 rounded to 2 dps is 173.26
173.2562 rounded to -1 dps is 170.0
]]--
local mult = 10^(dp or 0)
return math.floor(num * mult + 0.5)/mult
end
For rounding to a given amount of decimals (which can also be negative), I'd suggest the following solution that is combined from the findings already presented as answers, especially the inspiring one given by Pedro Gimeno. I tested a few corner cases I'm interested in but cannot claim that this makes this function 100% reliable:
function round(number, decimals)
local scale = 10^decimals
local c = 2^52 + 2^51
return ((number * scale + c ) - c) / scale
end
These cases illustrate the round-halfway-to-even property (which should be the default on most machines):
assert(round(0.5, 0) == 0)
assert(round(-0.5, 0) == 0)
assert(round(1.5, 0) == 2)
assert(round(-1.5, 0) == -2)
assert(round(0.05, 1) == 0)
assert(round(-0.05, 1) == 0)
assert(round(0.15, 1) == 0.2)
assert(round(-0.15, 1) == -0.2)
I'm aware that my answer doesn't handle the third case of the actual question, but in favor of being IEEE-754 compliant, my approach makes sense. So I'd expect that the results depend on the current rounding mode set in the FPU with FE_TONEAREST being the default. And that's why it seems high likely that after setting FE_TOWARDZERO (however you can do that in Lua) this solution would return exactly the results that were asked for in the question.
Try using math.ceil(number + 0.5) This is according to this Wikipedia page. If I'm correct, this is only rounding positive integers. you need to do math.floor(number - 0.5) for negatives.
If it's useful to anyone, i've hash-ed out a generic version of LUA's logic, but this time for truncate() :
**emphasized text pre-apologize for not knowing lua-syntax, so this is in AWK/lua mixture, but hopefully it should be intuitive enough
-- due to lua-magic alrdy in 2^(52-to-53) zone,
-- has to use a more coarse-grained delta than
-- true IEEE754 double machineepsilon of 2^-52
function trunc_lua(x,s) {
return \
((x*(s=(-1)^(x<-x)) \
- 2^-1 + 2^-50 \ -- can also be written as
\ -- 2^-50-5^0/2
- _LUAMAGIC \ -- if u like symmetric
\ -- code for fun
+ _LUAMAGIC \
) *(s) };
It's essentially the same concept as rounding, but force-processing all inputs in positive-value zone, with a -1*(0.5-delta) offset. The smallest delta i could attain is 2^-52 ~ 2.222e-16.
The lua-magic values must come after all those pre-processing steps, else precision-loss may occur. And finally, restore original sign of input.
The 2 "multiplies" are simply low-overhead sign-flipping. sign-flips 4 times for originally negative values (2 manual flips and round-trip to end of mantissa), while any x >= 0, including that of -0.0, only flips twice. All tertiary function calling, float division, and integer modulus is avoided, with only 1 conditional check for x<0.
usage notes :
(1) doesn't perform checks on input for invalid or malicious payload,
(2) doesn't use quickly check for zero,
(3) doesn't check for extreme inputs that may render this logic moot, and
(4) doesn't attempt to pretty format the value
if not exist math.round
function math.round(x, n)
return tonumber(string.format("%." .. n .. "f", x))
end
I am trying to return very long integer number but my result returns as
"7.6561197971049e+016".
How do I make it return 76561197971049296 ?
local id64 = 76561197960265728
Z = string.match("STEAM_0:0:5391784", 'STEAM_%d+:%d+:(%d+)')
Y = string.match("STEAM_0:0:5391784", 'STEAM_%d+:(%d+):%d+')
--For 64-bit systems
--Let X, Y and Z constants be defined by the SteamID: STEAM_X:Y:Z.
--Let V be SteamID64 identifier of the account type (0x0110000100000000 in hexadecimal format).
--Using the formula W=Z*2+V+Y
if Z == nil then
return "none"
else
return Z*2+id64+Y
end
I installed lbc arbitrary precision now with this code
return bc.add(bc.number(id64),bc.number(2)):tostring()
it returns 70000000000000002 but if I delete 3 digits from id64 it displays correctly.
How can I get correct result without deleting the digits?
You need to use strings for long numbers. Otherwise, the Lua lexer converts them to doubles and loses precision in this case. Here is code using my lbc:
local bc=require"bc"
local id64=bc.number"76561197960265728"
local Y,Z=string.match("STEAM_0:0:5391784",'STEAM_%d+:(%d+):(%d+)')
if Z == nil then
return "none"
else
return (Z*2+id64+Y):tostring()
end
check out this library for arbitrary precision arithmetics. this so post might be of interest to you as well.
Assuming your implementation of Lua supports that many significant digits in the number type, your return statement is returning that result.
You're probably seeing exponential notation when you convert the number to a string or printing it. You can use the string.format function to control the conversion:
assert( "76561197971049296" == string.format("%0.17g", 76561197971049296))
If number is an IEEE-754 double, then it doesn't work. You do have to know how your Lua is implemented and keep in mind the the technical limitations.
If you have luajit installed, you can do this:
local ffi = require("ffi")
steamid64 = tostring(ffi.new("uint64_t", 76561197960265728) + ffi.new("uint64_t", tonumber(accountid)))
steamid64 = string.sub(steamid64, 1, -4) -- to remove 'ULL at the end'
Hope it helps.
I need a base converter function for Lua. I need to convert from base 10 to base 2,3,4,5,6,7,8,9,10,11...36 how can i to this?
In the string to number direction, the function tonumber() takes an optional second argument that specifies the base to use, which may range from 2 to 36 with the obvious meaning for digits in bases greater than 10.
In the number to string direction, this can be done slightly more efficiently than Nikolaus's answer by something like this:
local floor,insert = math.floor, table.insert
function basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return sign .. table.concat(t,"")
end
This creates fewer garbage strings to collect by using table.concat() instead of repeated calls to the string concatenation operator ... Although it makes little practical difference for strings this small, this idiom should be learned because otherwise building a buffer in a loop with the concatenation operator will actually tend to O(n2) performance while table.concat() has been designed to do substantially better.
There is an unanswered question as to whether it is more efficient to push the digits on a stack in the table t with calls to table.insert(t,1,digit), or to append them to the end with t[#t+1]=digit, followed by a call to string.reverse() to put the digits in the right order. I'll leave the benchmarking to the student. Note that although the code I pasted here does run and appears to get correct answers, there may other opportunities to tune it further.
For example, the common case of base 10 is culled off and handled with the built in tostring() function. But similar culls can be done for bases 8 and 16 which have conversion specifiers for string.format() ("%o" and "%x", respectively).
Also, neither Nikolaus's solution nor mine handle non-integers particularly well. I emphasize that here by forcing the value n to an integer with math.floor() at the beginning.
Correctly converting a general floating point value to any base (even base 10) is fraught with subtleties, which I leave as an exercise to the reader.
you can use a loop to convert an integer into a string containting the required base. for bases below 10 use the following code, if you need a base larger than that you need to add a line that mapps the result of x % base to a character (usign an array for example)
x = 1234
r = ""
base = 8
while x > 0 do
r = "" .. (x % base ) .. r
x = math.floor(x / base)
end
print( r );