lua大整数运算的问题

1,987 views
Skip to first unread message

姚尉

unread,
Aug 22, 2015, 6:49:36 AM8/22/15
to openresty
hi,all

最近用lua处理某些大整数的时候发现不对劲

下面这条语句的结果是:10992432728506384
print(string.format("%d", 186312419127226*59 + 49))
但是这个算术得到的结果应该是:10992432728506383

有人碰到过同样的问题吗?
不知道是因为string.format的问题呢,还是说lua本身计算的时候精度导致的,这个结果没有超过long型啊

而且逢9的算术好像都有问题比如:186312419127226*59 + 39

luajit也有同样的问题

lua 版本:5.1.5
luajit版本:2.1.0-alpha

64位操作系统

Lance

unread,
Aug 22, 2015, 7:12:42 AM8/22/15
to open...@googlegroups.com
lua 5.1 只支持到 32bit 数 ,而且印象中是所有整数都通过浮点数操作。
lua 5.2或者5.3 之后才加的64位整数和浮点数。

Lance

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html

姚尉

unread,
Aug 22, 2015, 8:40:26 AM8/22/15
to openresty

但是有一些超过32位的运算也是正确的,上面的例子改成print(string.format("%d", 186312419127226*59 + 48)) 结果是正确的,而且这个数肯定是超32位了的
如果只支持32位的话应该所有超过32位的运算都不会正确,而且lua5.1是用double来表示数字的,按道理运算应该没问题的

在 2015年8月22日星期六 UTC+8下午7:12:42,Lance Li写道:

Lance

unread,
Aug 22, 2015, 6:13:15 PM8/22/15
to open...@googlegroups.com
哦,你这个应该是浮点转整数的精度问题,如果不是直接的整数计算而是浮点模拟,基本所有的编程语言都有这个问题
--
Lance

Yichun Zhang (agentzh)

unread,
Aug 23, 2015, 7:53:43 AM8/23/15
to openresty
Hello!

2015-08-22 18:49 GMT+08:00 姚尉:
> 最近用lua处理某些大整数的时候发现不对劲
>
> 下面这条语句的结果是:10992432728506384
> print(string.format("%d", 186312419127226*59 + 49))
> 但是这个算术得到的结果应该是:10992432728506383
>
> 有人碰到过同样的问题吗?
> 不知道是因为string.format的问题呢,还是说lua本身计算的时候精度导致的,这个结果没有超过long型啊
>

在 LuaJIT 中,Lua number 的默认精度上限是双精度浮点数(double)。如果你想进行无精度损失的 64 位整数计算,须使用
FFI cdata 的包装整数类型。例如,对于你这里的例子:

local ffi = require "ffi"
local res = ffi.new("int64_t", 186312419127226)*59 + 49)
print(tostring(res)

使用 LuaJIT 运行这三行 Lua 代码得到的结果是

10992432728506383LL

正是你期望的值。

Regards,
-agentzh

Mike Green

unread,
Aug 23, 2015, 9:08:19 AM8/23/15
to open...@googlegroups.com
在lua-5.3.0中,结果是正确的,在lua-5.2.0中,是这么定义的:


449 /*
450 @@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned.
451 ** It must have at least 32 bits.
452 */
453 #define LUA_UNSIGNED    unsigned LUA_INT32

所有超过int32范围的数,在lua-5.2.0中,应该都是以double计算的。

PS: 感觉5.3.0之前的lua,就是小孩子的玩具~
> 写道:
>Hello!
>
>2015-08-22 18:49 GMT+08:00 姚尉:
>> 最近用lua处理某些大整数的时候发现不对劲
>>
>> 下面这条语句的结果是:10992432728506384
>> print(string.format("%d", 186312419127226*59 + 49))
>> 但是这个算术得到的结果应该是:10992432728506383
>>
>> 有人碰到过同样的问题吗?
>> 不知道是因为string.format的问题呢,还是说lua本身计算的时候精度导致的,这个结果没有超过long型啊
>>
>
>在 LuaJIT 中,Lua number 的默认精度上限是双精度浮点数(double)。如果你想进行无精度损失的 64 位整数计算,须使用
>FFI cdata 的包装整数类型。例如,对于你这里的例子:
>
>    local ffi = require "ffi"
>    local res = ffi.new("int64_t", 186312419127226)*59 + 49)
>    print(tostring(res)
>
>使用 LuaJIT 运行这三行 Lua 代码得到的结果是
>
>    10992432728506383LL
>
>正是你期望的值。
>
>Regards,
>-agentzh
>
>-- 
>-- 
>邮件来自列表“openresty”,专用于技术讨论!
>订阅: 请发空白邮件到 openresty...@googlegroups.com


Yichun Zhang (agentzh)

unread,
Aug 23, 2015, 8:38:15 PM8/23/15
to openresty
Hello!

2015-08-23 19:53 GMT+08:00 Yichun Zhang (agentzh):
> 在 LuaJIT 中,Lua number 的默认精度上限是双精度浮点数(double)。如果你想进行无精度损失的 64 位整数计算,须使用
> FFI cdata 的包装整数类型。例如,对于你这里的例子:
>
> local ffi = require "ffi"
> local res = ffi.new("int64_t", 186312419127226)*59 + 49)
> print(tostring(res)
>

好吧,这可以进一步化简为

$ luajit -e 'print(186312419127226LL*59 + 49)'
10992432728506383LL

不用显式地使用 ffi 模块。貌似这已经足够简单了 :)

Regards,
-agentzh

Yichun Zhang (agentzh)

unread,
Aug 23, 2015, 8:43:15 PM8/23/15
to openresty
Hello!

2015-08-23 21:06 GMT+08:00 Mike Green:
> PS: 感觉5.3.0之前的lua,就是小孩子的玩具~
>

呃,我对此并不敢苟同,呵呵。

默认为 number 使用 64-bit 整型对性能损耗很大。比如在标准 Lua 5.3 解释器中,TValue 类型长达 128 位。而在
LuaJIT 2 中,TValue 只有 64 位。TValue 的长度对一般的 Lua 代码的执行性能影响很大。

Regards,
-agentzh

DeJiang Zhu

unread,
Aug 23, 2015, 10:15:59 PM8/23/15
to open...@googlegroups.com
hi,春哥

在 2015年8月24日 上午8:38,Yichun Zhang (agentzh) <age...@gmail.com>写道:

好吧,这可以进一步化简为

    $ luajit -e 'print(186312419127226LL*59 + 49)'
    10992432728506383LL

不用显式地使用 ffi 模块。貌似这已经足够简单了 :)

我觉得这样还不够方便,在一般场景,我们可能需要这么做,才能得到标准的 string

local long_number = 1LL * number1 * number2
local long_str = tostring(long_number)
local nomal_str = string.sub(long_str, 1, -3)


我在想,是不是可以类似 ngx.null,引入 ngx.int64 呢

local nomal_str = tostring(ngx.int64(number1) * number2)

1. 用 ngx.int64 显式的转化,支持 string,lua number 传入
2. tostring 不再加入 LL 这个尾巴

Mike Green

unread,
Aug 23, 2015, 11:52:39 PM8/23/15
to open...@googlegroups.com
LuaJIT 2 中,TValue 只有 64 位????

在amd64上,Value *指针应该也是64位的吧?就算tt_用的是32位,64+32也是96位啊,与128位并无不同。






> 写道:
>Hello!
>
>2015-08-23 21:06 GMT+08:00 Mike Green:
>> PS: 感觉5.3.0之前的lua,就是小孩子的玩具~
>>
>
>呃,我对此并不敢苟同,呵呵。
>
>默认为 number 使用 64-bit 整型对性能损耗很大。比如在标准 Lua 5.3 解释器中,TValue 类型长达 128 位。而在
>LuaJIT 2 中,TValue 只有 64 位。TValue 的长度对一般的 Lua 代码的执行性能影响很大。
>
>Regards,
>-agentzh
>
>-- 
>-- 
>邮件来自列表“openresty”,专用于技术讨论!
>订阅: 请发空白邮件到 openresty...@googlegroups.com


Yichun Zhang (agentzh)

unread,
Aug 26, 2015, 10:44:42 AM8/26/15
to openresty
Hello!

2015-08-24 10:15 GMT+08:00 DeJiang Zhu:
> 我觉得这样还不够方便,在一般场景,我们可能需要这么做,才能得到标准的 string
>
> local long_number = 1LL * number1 * number2
> local long_str = tostring(long_number)
> local nomal_str = string.sub(long_str, 1, -3)
>
> 我在想,是不是可以类似 ngx.null,引入 ngx.int64 呢
>

呃,不喜欢 ngx.int64. 感觉这里我们只是需要一个不带 LL 后缀的 tostring() :)

Regards,
-agentzh

Yichun Zhang (agentzh)

unread,
Aug 26, 2015, 10:50:40 AM8/26/15
to openresty
Hello!

2015-08-24 11:51 GMT+08:00 Mike Green:
> LuaJIT 2 中,TValue 只有 64 位????
>

是的。你可以自己在 gdb 里面验证:

(gdb) p sizeof(TValue)
$1 = 8

只有 8 个字节。

双精度浮点数是 64 位的,利用 NaN-tagging 融合其他类型的 TValue.

> 在amd64上,Value *指针应该也是64位的吧?就算tt_用的是32位,64+32也是96位啊,与128位并无不同。
>

LuaJIT 目前只支持 32 位指针。LuaJIT 正在开发中的 GC64 模式支持 47 位指针(虽然不及 64
位指针,但地址空间也已经非常够用了)。在 GC64 模式下,TValue 仍然保持 64 位,因为这对性能至关重要。见下面的讨论:

http://comments.gmane.org/gmane.comp.lang.lua.luajit/5956

Regards,
-agentzh

DeJiang Zhu

unread,
Aug 27, 2015, 10:19:55 AM8/27/15
to open...@googlegroups.com
hi,春哥

在 2015年8月26日 下午10:44,Yichun Zhang (agentzh) <age...@gmail.com>写道:

呃,不喜欢 ngx.int64. 感觉这里我们只是需要一个不带 LL 后缀的 tostring() :)

我还想有支持 从 string 转 int64 的 tonumber :)

Chunhui Shi

unread,
Jun 12, 2016, 2:36:17 AM6/12/16
to openresty
我目前项目中采用openresty 做后台服务,遇到一个问题就是openresty 内置的lua版本是5.1,默认使用内置的luajit
,都不支持int64, 而且我需要使用cjson 来encode和decode int64,本来想把lua5.3编译到openresty里面,发现编译失败。
想问一下,有没有办法把lua5.3编译进openresty里面? 或者有办法是openresty里面的luajit2.1支持int64? 

春哥,请问这种情况有没有好点的解决办法啊?

DeJiang Zhu

unread,
Jun 13, 2016, 9:56:16 AM6/13/16
to open...@googlegroups.com
Hello,

眼下最方便的还是用 string 来表示 int64

cheng song

unread,
Jul 25, 2019, 10:39:57 AM7/25/19
to openresty
我现在遇到一个问题,我的请求体当中有一个字段是18位长度的全是数字的字符串,类似"200009130000219011",当我取出来以后我需要对这个数字进行取模,请问有什么好办法吗

在 2016年6月13日星期一 UTC+8下午9:56:16,doujiang写道:
Hello,

眼下最方便的还是用 string 来表示 int64
在 2016年6月12日 下午2:36,Chunhui Shi <shichun...@gmail.com>写道:
我目前项目中采用openresty 做后台服务,遇到一个问题就是openresty 内置的lua版本是5.1,默认使用内置的luajit
,都不支持int64, 而且我需要使用cjson 来encode和decode int64,本来想把lua5.3编译到openresty里面,发现编译失败。
想问一下,有没有办法把lua5.3编译进openresty里面? 或者有办法是openresty里面的luajit2.1支持int64? 

春哥,请问这种情况有没有好点的解决办法啊?

On Saturday, August 22, 2015 at 6:49:36 PM UTC+8, 姚尉 wrote:
hi,all

最近用lua处理某些大整数的时候发现不对劲

下面这条语句的结果是:10992432728506384
print(string.format("%d", 186312419127226*59 + 49))
但是这个算术得到的结果应该是:10992432728506383

有人碰到过同样的问题吗?
不知道是因为string.format的问题呢,还是说lua本身计算的时候精度导致的,这个结果没有超过long型啊

而且逢9的算术好像都有问题比如:186312419127226*59 + 39

luajit也有同样的问题

lua 版本:5.1.5
luajit版本:2.1.0-alpha

64位操作系统

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 open...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 open...@googlegroups.com

xiaobiao zhao

unread,
Jul 25, 2019, 8:21:09 PM7/25/19
to open...@googlegroups.com
建议使用FFI包装一层C函数给lua调用

cheng song <zabbi...@gmail.com> 于2019年7月25日周四 下午10:40写道:
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
---
您收到此邮件是因为您订阅了Google网上论坛上的“openresty”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到openresty+...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/openresty/ff878bd3-a677-40f9-ba5c-1ca21d7c76c8%40googlegroups.com

tokers

unread,
Jul 25, 2019, 9:37:08 PM7/25/19
to openresty
Hello!

如果模数可以用整数表示,直接用取模运算的性质就可以算了。

设模数为 m

local str_byte = string.byte
local rest = 0
for i = 1,#str do
   
local b = str_byte(str, i, i) - 48
    rest
= (rest * 10 + b) % m
end


cheng song

unread,
Jul 25, 2019, 11:23:25 PM7/25/19
to openresty
非常感谢。。简单暴力的解决了我这个问题。

在 2019年7月26日星期五 UTC+8上午9:37:08,tokers写道:
Reply all
Reply to author
Forward
0 new messages