十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
浮点数表示法的确存在精度丢失的问题,是由于最低有效位的限制造成的。而且一般其实际表示的数值会比规定的要小。比如2.6的浮点数表示为40266666H,而该数实际的值是2.5999999,这样计算的结果是0.0999999比0.1小,不能输出0.1,产生精度丢失,而如果将其表示更改为40266667H,其表示的实际值是2.6000001,而这个数可以输出0.1的结果的。所以如果要使计算能够得出正确结果,可以尝试在输入的时候将有效位数扩展,以确保得出正确结果。
创新互联-云计算及IDC服务提供商,涵盖公有云、IDC机房租用、成都电信服务器托管、等保安全、私有云建设等企业级互联网基础服务,联系电话:18980820575
比如要输出2.6的结果,可以设sx=2.6000001,这样可以使浮点数表示结果为大于2.6的尽可能小的值。如果要输出2.1的结果,可以设sx=2.1000001。
int k=0;
float sx=2.6000001;
在进行数据计算时,小数也就是浮点数拥有不低的出场率。在常人看来,机器也就是计算机的数据运算是不会出错的,没错,计算机进行数据运算的确不会犯错,但小数运算的误差是免不了的。
来试一试。
在JS中写上console.log(0.3-0.1);输出到控制台
是不是出乎意料,简单的0.3-0.1=0.2这样一道小学算术都没算对。
在对于浮点数的四则运算,几乎所有的编程语言都会有类似精度误差的问题。
只不过在 C++/C#/Java 这些语言中已经封装好了方法来避免精度的问题,而 JavaScript 是一门弱类型的语言,从设计思想上就没有对浮点数有个严格的数据类型,所以精度误差的问题就显得格外突出,无法避免。
那么为什么会有这个误差呢,误差有没有办法解决呢。
首先看计算机是怎么进行运算的。大家都知道计算机是二进制运算。那么要计算0.3减0.1,就要先进行换算。
console.log("0.3="+(0.3).toString(2));
console.log("0.1="+(0.1).toString(2));
console.log("0.3-0.1="+(0.3 - 0.1).toString(2));
输出结果如下图:
0.3与0.1转换为二进制的浮点数都是无限循环小数。但由于浮点数精度有限被强行截断,所以转回十进制输出的数据会有误差。
那么如何解决这个问题。
最简单的解决方案就是给出明确的精度要求,在返回值的过程中,计算机会自动四舍五入。
console.log((0.3-0.1).toFixed(2));//输出的结果是0.20;
然而这样子解决有点勉强。
再看下面的方法
var s = Math.pow(10,8);
console.log((0.3 * s - 0.1 * s)/s);
输出后结果为0.2,没有误差。为什么,上面是什么意思。
原来为了避免产生精度差异,我们要把需要计算的数字乘以 10 的 n 次幂,换算成计算机能够精确识别的整数,然后再除以 10 的 n 次幂,就能够得到准确的结果了。
大部分编程语言都是这样处理精度差异的,这里就借用过来处理一下 JS 中的浮点数精度误差。
在Excel进行计算时在计算机中是转换成二进制进算然后保留数值的,所以会出现误差。解决方法:
1、打开excel表格,在单元格A1中输入数字“2.88”,在单元格B1中输入数字“5.89”。
2、在C1单元格中输入计算公式:=(ROUND(A1,2))+ROUND(B1,2),意思为使用ROUND函数确保小数位为2位。
3、点击回车生成函数公式计算结果,得到的数值为“8.77”。
4、复制C1单元格,在C2点击右键,选择“粘贴数值”。
5、粘贴之后,可以看到计算得到的数值是小数点显示后两位,没有出现误差。
首先,看一下浮点数误差原因
浮点数的误差的产生一般由于两个原因
1)由于计算机内部以二进制保存,所以十进制的有限位的小数,在计算机内部会是一个无限位的小数。
例如 十进制的0.9虽然只有一位小数,转成2进制是无限循环小数0.1110011001100110011...
2)计算机保存浮点数的精度有限,例如float可以保留十进制最多7位(二进制23位)有效数字,double 可以保留十进制15~16位(二进制52位)有效数字。那有效数字以后的就被忽略了。
例如上面的0.9的表示受精度所限,精度以后的就被忽略了,这样
float时,它是0.89999998
double时,它是0.90000000000000002
每一次对浮点数的运算都会导致小误差,所以比较的时候不能用等于号 要这样写
i - 10.0 = 0.0000000001 这样就会减少点误差,而且你的第二个程序也会报yes了
浮点数的比较很麻烦,像while(sx=0.1)这个等号很不保险
要判断一个浮点数是否等于另外一个浮点数,一般是求二者的差,差的绝对值小于某给定值就算相等 像这样:
while((sx-0.1)0.00001(0.1-sx)0.00001)
{
sx=0;
printf("0.1=1\n");
}
总之,在程序中应该尽量避免浮点数的比较
Golang Float乘Float高精度,转Int高精度。
使用big.Float
bigF1 := new(big.Float).SetFloat64(f1)
bigF2 := new(big.Float).SetFloat64(f2)
mul := new(big.Float).Mul(bigF1, bigF2)
转Int,先用上面的方法转为big.Float,再用.String转为字符串。
new(big.Int).SetString(bigFloat, 10) // 即可转为big.Int
// big.Int可转为常用的int类型。
// big.Float可转为常用的Float类型。
// big.Float不能直接转为Int类型。
func Sub(x float64, y float64, more ...float64) float64 {
floatX := new(big.Float).SetFloat64(x)
floatY := new(big.Float).SetFloat64(y)
result := new(big.Float).Sub(floatX, floatY)
if len(more) 0 {
for _, m := range more {
floatM := new(big.Float).SetFloat64(m)
result = new(big.Float).Sub(result, floatM)
}
}
f, _ := strconv.ParseFloat(result.String(), 64)
return f
}