想请教一个关于精度丢失的问题

时间:2021-05-15 23:02:19
最近被精度丢失困扰了好久,想出了一个办法,干脆用分母和分子都是整型的分数来代替小数,想请教下各位前辈,这个方法可行性如何?会不会踩到新的坑?

11 个解决方案

#1


你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

#2


引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?

#3


你想要多高的精度?

#4


引用 2 楼 q199308040000 的回复:
Quote: 引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?


要彻底解决精度问题,需要用符号运算。
要减小精度损失,我们有一系列数值计算方式来实现。

#5


引用 3 楼 cheng2005的回复:
你想要多高的精度?

刚才百度了一下符号运算,大致有了一个印象,貌似其实就是代数,想再请教一下大神,如果在解方程的过程中出现了精度丢失怎么办?

#6


引用 4 楼 caozhy的回复:
Quote: 引用 2 楼 q199308040000 的回复:

Quote: 引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?


要彻底解决精度问题,需要用符号运算。
要减小精度损失,我们有一系列数值计算方式来实现。

刚才百度了一下符号运算,大致有了一个印象,貌似其实就是代数,想再请教一下大神,如果在解方程的过程中出现了精度丢失怎么办?

#7


你用decimal试试呢?只要浮点型运算,精度丢失就不可避免的。
只能说decimal比double更靠谱一点。

#8


用decimal可以减小出现误差的概率和误差量,因为decimal也是浮点型所以不可避免会出现误差。
根本原因在于计算机本身就是2进制的,对于浮点数计算机将小数点前面的数字进行除2取余数,小数点后面是成2取整数,对于乘法基本上只有末尾是0和5才可能最终得到没有小数的整数。

举例:
我们按照乘以 2 取整数位的方法,把 0.1 表示为二进制:
(1) 0.1 x 2 = 0.2  取整数位 0 得 0.0
(2) 0.2 x 2 = 0.4  取整数位 0 得 0.00
(3) 0.4 x 2 = 0.8  取整数位 0 得 0.000
(4) 0.8 x 2 = 1.6  取整数位 1 得 0.0001
(5) 0.6 x 2 = 0.2  取整数位 1 得 0.00011
(6) 0.2 x 2 = 0.4  取整数位 0 得 0.000110
(7) 0.4 x 2 = 0.8  取整数位 0 得 0.0001100
(8) 0.8 x 2 = 1.6  取整数位 1 得 0.00011001
(9) 0.6 x 2 = 1.2  取整数位 1 得 0.000110011
(n) ...
我们得到一个无限循环的二进制小数 0.000110011…

#9


关于精度丢失实际上通用的做法是保留n位结果小数就用long把原始数据乘以10的n+2次方,然后用long计算

#10


建议用一个结构体表示,一个表示精度位,例如小数点三位,该数为-3,一个表示乘以小数点后位数的十次方的整数。例如1.234表示为 {3,1234}

#11


看是什么精度
如果是定点小数,可以直接用整数、长整型存储小数,然后程序里约定一个放大系数,这样进行四则运算时都不会损失精度
如果你的小数值是两数相除得到的,楼主的办法虽然可以解决存储问题,但是如果涉及到两个小数相加,损失精度依然是必然的
如果值是开方、自然对数、圆周率之类的,就更没办法了

归根结底,因为一个有限小数转换为二进制时,可能变成一个无限小数,但计算机里不可能存无限长度的数,所以丢失精度是必然的
从另一个角度看,整数之所以没有精度问题,是因为整数本身就是离散的,“整数1和整数100之间有多少个整数?”,这个数量是有限的;而小数是连续的数值,“小数1.1和1.2之间有多少个小数?”,答案是无限多个小数。而计算机里只能存储离散的量,所以你要存储的数值不幸处于它能表示的两个离散值之间时,精度丢失就是必然的。

#1


你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

#2


引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?

#3


你想要多高的精度?

#4


引用 2 楼 q199308040000 的回复:
Quote: 引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?


要彻底解决精度问题,需要用符号运算。
要减小精度损失,我们有一系列数值计算方式来实现。

#5


引用 3 楼 cheng2005的回复:
你想要多高的精度?

刚才百度了一下符号运算,大致有了一个印象,貌似其实就是代数,想再请教一下大神,如果在解方程的过程中出现了精度丢失怎么办?

#6


引用 4 楼 caozhy的回复:
Quote: 引用 2 楼 q199308040000 的回复:

Quote: 引用 1 楼 caozhy的回复:
你的方法只能表示实数,类似pi sqrt(2) 之类的有理数呢。

最好是全部用符号运算,而不是数值运算。

那再请教一下,对于精度丢失大家一般是怎么解决的?


要彻底解决精度问题,需要用符号运算。
要减小精度损失,我们有一系列数值计算方式来实现。

刚才百度了一下符号运算,大致有了一个印象,貌似其实就是代数,想再请教一下大神,如果在解方程的过程中出现了精度丢失怎么办?

#7


你用decimal试试呢?只要浮点型运算,精度丢失就不可避免的。
只能说decimal比double更靠谱一点。

#8


用decimal可以减小出现误差的概率和误差量,因为decimal也是浮点型所以不可避免会出现误差。
根本原因在于计算机本身就是2进制的,对于浮点数计算机将小数点前面的数字进行除2取余数,小数点后面是成2取整数,对于乘法基本上只有末尾是0和5才可能最终得到没有小数的整数。

举例:
我们按照乘以 2 取整数位的方法,把 0.1 表示为二进制:
(1) 0.1 x 2 = 0.2  取整数位 0 得 0.0
(2) 0.2 x 2 = 0.4  取整数位 0 得 0.00
(3) 0.4 x 2 = 0.8  取整数位 0 得 0.000
(4) 0.8 x 2 = 1.6  取整数位 1 得 0.0001
(5) 0.6 x 2 = 0.2  取整数位 1 得 0.00011
(6) 0.2 x 2 = 0.4  取整数位 0 得 0.000110
(7) 0.4 x 2 = 0.8  取整数位 0 得 0.0001100
(8) 0.8 x 2 = 1.6  取整数位 1 得 0.00011001
(9) 0.6 x 2 = 1.2  取整数位 1 得 0.000110011
(n) ...
我们得到一个无限循环的二进制小数 0.000110011…

#9


关于精度丢失实际上通用的做法是保留n位结果小数就用long把原始数据乘以10的n+2次方,然后用long计算

#10


建议用一个结构体表示,一个表示精度位,例如小数点三位,该数为-3,一个表示乘以小数点后位数的十次方的整数。例如1.234表示为 {3,1234}

#11


看是什么精度
如果是定点小数,可以直接用整数、长整型存储小数,然后程序里约定一个放大系数,这样进行四则运算时都不会损失精度
如果你的小数值是两数相除得到的,楼主的办法虽然可以解决存储问题,但是如果涉及到两个小数相加,损失精度依然是必然的
如果值是开方、自然对数、圆周率之类的,就更没办法了

归根结底,因为一个有限小数转换为二进制时,可能变成一个无限小数,但计算机里不可能存无限长度的数,所以丢失精度是必然的
从另一个角度看,整数之所以没有精度问题,是因为整数本身就是离散的,“整数1和整数100之间有多少个整数?”,这个数量是有限的;而小数是连续的数值,“小数1.1和1.2之间有多少个小数?”,答案是无限多个小数。而计算机里只能存储离散的量,所以你要存储的数值不幸处于它能表示的两个离散值之间时,精度丢失就是必然的。