找回密码
 立即注册

QQ登录

只需一步,快速开始

Erik.Xue 讲师达人认证 悬赏达人认证 活字格认证 Wyn认证
超级版主   /  发表于:2022-4-18 10:04  /   查看:2925  /  回复:0
本帖最后由 Erik.Xue 于 2022-4-18 10:07 编辑

最近,有不少格友发现了一个小问题。问题表象是,当引入外联表或创建外联表副本时,因为格友需要使用一些专有数据库的数据表,比如用友U9等这类数据库中的数据表,这类数据表有一个特点就是ID字段非常长,一般为16位或16位以上的数字。像这样: image.png376718139.png
当然,这是在外联数据库中的样子,当将此类数据表连接到活字格后,或者在活字格中创建为外联表副本后,就会发现,数据表中的ID字段的值都变成了这样:


image.png881537170.png


这是为什么?此时就引出了一个词儿——精度丢失


首先,先介绍下什么是精度丢失。


通俗易懂的解释就是,比如一个数 1 ÷ 3 = 0.33333333...3会一直无限循环,数学可以表示,但是计算机要存储,方便下次取出来再使用,但0.333333......这个数无限循环,计算机就没办法存储了。再大的内存也存不下,所以不能存储一个相对于数学来说的值,那就只能存储一个近似值,所以当计算机存储后再取出来用的时候就会出问题。

而在JavaScript中存储小数和其他强类型语言比如Java、C#等都不同,JavaScript中所有数字包括整数和小数都只有一种类型,即 Number类型,它的实现遵循IEEE754标准,IEEE754标准的内容都有什么这个都不重要,我们只需要记住以下一点:


JavaScript以64位双精度浮点数存储所有Number类型值,即计算机最多存储64位二进制数。


这样的存储结构优点是可以归一化处理整数和小数,节省存储空间。


其中,精度丢失也包括《大数危机》


比如:9999999999999999 == 10000000000000001 (true)
image.png133447875.png

16位和17位的数竟然相等??!!


原因是大整数的精度丢失和浮点数本质上是一样的,计算机存储的为二进制,而能存储的二进制其实只有62位,超出就会有舍入操作,因此JavaScript中能精确表示的最大整数是Math.pow(2, 53),十进制即9007199254740992大于9007199254740992的就会丢失精度。


以上,可以知道看似有穷的数字,在计算机的二进制表示里确实无穷的,由于存储位数限制因此存在“舍去”,精度丢失就发生了,此时两个大数在计算机中的二进制正数就相等了。


其实,在《淘宝》早期的订单系统中把订单号当做数字处理,后来随着订单号暴增,已经超过了9007199254740992,最终的解法是把订单号改成字符串处理。

也就是说,在活字格中,为了兼容浏览器的大数显示,所以在外联表连入活字格后,大数字段也会有精度丢失的现象。

所以,解决办法有两种:

  • 将链接入活字格的外联表先包一层视图,设置数据表中的整型ID为字符串类型,如在sqlserver中:    image.png13262938.png
  • 更改外联库的字段类型为字符串,连接入活字格即可。









0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部