十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
浮點數(shù)表示法的確存在精度丟失的問題,是由于最低有效位的限制造成的。而且一般其實際表示的數(shù)值會比規(guī)定的要小。比如2.6的浮點數(shù)表示為40266666H,而該數(shù)實際的值是2.5999999,這樣計算的結果是0.0999999比0.1小,不能輸出0.1,產(chǎn)生精度丟失,而如果將其表示更改為40266667H,其表示的實際值是2.6000001,而這個數(shù)可以輸出0.1的結果的。所以如果要使計算能夠得出正確結果,可以嘗試在輸入的時候將有效位數(shù)擴展,以確保得出正確結果。
創(chuàng)新互聯(lián)-云計算及IDC服務提供商,涵蓋公有云、IDC機房租用、成都電信服務器托管、等保安全、私有云建設等企業(yè)級互聯(lián)網(wǎng)基礎服務,聯(lián)系電話:18980820575
比如要輸出2.6的結果,可以設sx=2.6000001,這樣可以使浮點數(shù)表示結果為大于2.6的盡可能小的值。如果要輸出2.1的結果,可以設sx=2.1000001。
int k=0;
float sx=2.6000001;
在進行數(shù)據(jù)計算時,小數(shù)也就是浮點數(shù)擁有不低的出場率。在常人看來,機器也就是計算機的數(shù)據(jù)運算是不會出錯的,沒錯,計算機進行數(shù)據(jù)運算的確不會犯錯,但小數(shù)運算的誤差是免不了的。
來試一試。
在JS中寫上console.log(0.3-0.1);輸出到控制臺
是不是出乎意料,簡單的0.3-0.1=0.2這樣一道小學算術都沒算對。
在對于浮點數(shù)的四則運算,幾乎所有的編程語言都會有類似精度誤差的問題。
只不過在 C++/C#/Java 這些語言中已經(jīng)封裝好了方法來避免精度的問題,而 JavaScript 是一門弱類型的語言,從設計思想上就沒有對浮點數(shù)有個嚴格的數(shù)據(jù)類型,所以精度誤差的問題就顯得格外突出,無法避免。
那么為什么會有這個誤差呢,誤差有沒有辦法解決呢。
首先看計算機是怎么進行運算的。大家都知道計算機是二進制運算。那么要計算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轉換為二進制的浮點數(shù)都是無限循環(huán)小數(shù)。但由于浮點數(shù)精度有限被強行截斷,所以轉回十進制輸出的數(shù)據(jù)會有誤差。
那么如何解決這個問題。
最簡單的解決方案就是給出明確的精度要求,在返回值的過程中,計算機會自動四舍五入。
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,沒有誤差。為什么,上面是什么意思。
原來為了避免產(chǎn)生精度差異,我們要把需要計算的數(shù)字乘以 10 的 n 次冪,換算成計算機能夠精確識別的整數(shù),然后再除以 10 的 n 次冪,就能夠得到準確的結果了。
大部分編程語言都是這樣處理精度差異的,這里就借用過來處理一下 JS 中的浮點數(shù)精度誤差。
在Excel進行計算時在計算機中是轉換成二進制進算然后保留數(shù)值的,所以會出現(xiàn)誤差。解決方法:
1、打開excel表格,在單元格A1中輸入數(shù)字“2.88”,在單元格B1中輸入數(shù)字“5.89”。
2、在C1單元格中輸入計算公式:=(ROUND(A1,2))+ROUND(B1,2),意思為使用ROUND函數(shù)確保小數(shù)位為2位。
3、點擊回車生成函數(shù)公式計算結果,得到的數(shù)值為“8.77”。
4、復制C1單元格,在C2點擊右鍵,選擇“粘貼數(shù)值”。
5、粘貼之后,可以看到計算得到的數(shù)值是小數(shù)點顯示后兩位,沒有出現(xiàn)誤差。
首先,看一下浮點數(shù)誤差原因
浮點數(shù)的誤差的產(chǎn)生一般由于兩個原因
1)由于計算機內(nèi)部以二進制保存,所以十進制的有限位的小數(shù),在計算機內(nèi)部會是一個無限位的小數(shù)。
例如 十進制的0.9雖然只有一位小數(shù),轉成2進制是無限循環(huán)小數(shù)0.1110011001100110011...
2)計算機保存浮點數(shù)的精度有限,例如float可以保留十進制最多7位(二進制23位)有效數(shù)字,double 可以保留十進制15~16位(二進制52位)有效數(shù)字。那有效數(shù)字以后的就被忽略了。
例如上面的0.9的表示受精度所限,精度以后的就被忽略了,這樣
float時,它是0.89999998
double時,它是0.90000000000000002
每一次對浮點數(shù)的運算都會導致小誤差,所以比較的時候不能用等于號 要這樣寫
i - 10.0 = 0.0000000001 這樣就會減少點誤差,而且你的第二個程序也會報yes了
浮點數(shù)的比較很麻煩,像while(sx=0.1)這個等號很不保險
要判斷一個浮點數(shù)是否等于另外一個浮點數(shù),一般是求二者的差,差的絕對值小于某給定值就算相等 像這樣:
while((sx-0.1)0.00001(0.1-sx)0.00001)
{
sx=0;
printf("0.1=1\n");
}
總之,在程序中應該盡量避免浮點數(shù)的比較
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
}