2010-06-24 60 views
41

我一直在C#中使用Math.Round(myNumber, MidpointRounding.ToEven)做我的服務器端舍入,但是,用戶需要知道'活'的服務器端操作的結果是什麼意思(避免Ajax請求)創建一個JavaScript方法來複制C#使用的方法MidpointRounding.ToEven高斯/銀行家在JavaScript中四捨五入

MidpointRounding.ToEven是Gaussian/banker's rounding,這是一種很常見的會計系統舍入方法,描述爲here

有沒有人有這方面的經驗?我發現在線的例子,但他們沒有輪給出小數數的......

+0

好問題。是[這個腳本](http://dansnetwork.com/2009/11/30/round-half-to-even-with-javascript/)你發現的例子之一?它看起來可能是合適的,但我不是這方面的專家:-) – 2010-06-24 10:26:00

+0

它接近!但不幸的是沒有與負數工作 - 我會做一些改變,並在這裏發佈......謝謝:) – Jimbo 2010-06-27 11:12:17

回答

62
function evenRound(num, decimalPlaces) { 
    var d = decimalPlaces || 0; 
    var m = Math.pow(10, d); 
    var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors 
    var i = Math.floor(n), f = n - i; 
    var e = 1e-8; // Allow for rounding errors in f 
    var r = (f > 0.5 - e && f < 0.5 + e) ? 
       ((i % 2 == 0) ? i : i + 1) : Math.round(n); 
    return d ? r/m : r; 
} 

console.log(evenRound(1.5)); // 2 
console.log(evenRound(2.5)); // 2 
console.log(evenRound(1.535, 2)); // 1.54 
console.log(evenRound(1.525, 2)); // 1.52 

現場演示:http://jsfiddle.net/NbvBp/

對於什麼樣子的這種更嚴格的處理(我我從來沒有使用它),你可以試試這個BigNumber的實現。

+1

甜蜜地完成!適用於否定。 +2:P – Jimbo 2010-06-27 11:20:01

+10

這個答案是如此的經濟。 – 2012-06-30 00:23:09

+1

我想提出兩個補充。首先,我會檢查'Math.pow(10,d)'表達式(至少)的溢出/下溢。在這個錯誤上,並且當decimalPlaces爲正數時,返回num,否則重新提升該異常。其次,爲了彌補IEEE二進制轉換錯誤,我會將'f == 0.5'更改爲'f> = 0.499999999 && f <= 0.500000001' - 取決於您選擇的'epsilon'(不確定是否.toFixed(epsilon ) 足夠)。那麼你是金! – Marius 2013-10-04 15:32:50

2

接受的答案確實輪到給定數量的地方。在這個過程中,它調用toFixed將數字轉換爲一個字符串。由於這很貴,我提供下面的解決方案。它將以0.5結尾的數字舍入到最接近的偶數。它不處理四捨五入到任意數量的地方。

function even_p(n){ 
    return (0===(n%2)); 
}; 

function bankers_round(x){ 
    var r = Math.round(x); 
    return (((((x>0)?x:(-x))%1)===0.5)?((even_p(r))?r:(r-1)):r); 
}; 
+0

你的函數不允許指定保留 – 2015-12-08 19:57:24

+0

爲真的小數位數。這是留給更紅的:-)。閱讀:所有我需要的是正確的四捨五入到一個整數。 – soegaard 2015-12-08 20:00:08

+0

這是很棒的解決方案,謝謝! 這裏是你如何使它爲小數工作。看起來我必須發佈一個單獨的答案來顯示代碼... – xims 2016-10-12 13:11:56

2

這是@ soegaard的一個很好的解決方案。 這裏是一個小的變化,使得它爲小數點工作:

bankers_round(n:number, d:number=0) { 
    var x = n * Math.pow(10, d); 
    var r = Math.round(x); 
    var br = (((((x>0)?x:(-x))%1)===0.5)?(((0===(r%2)))?r:(r-1)):r); 
    return br/Math.pow(10, d); 
} 

雖然它 - 這裏有一些測試:

console.log(" 1.5 -> 2 : ", bankers_round(1.5)); 
console.log(" 2.5 -> 2 : ", bankers_round(2.5)); 
console.log(" 1.535 -> 1.54 : ", bankers_round(1.535, 2)); 
console.log(" 1.525 -> 1.52 : ", bankers_round(1.525, 2)); 

console.log(" 0.5 -> 0 : ", bankers_round(0.5)); 
console.log(" 1.5 -> 2 : ", bankers_round(1.5)); 
console.log(" 0.4 -> 0 : ", bankers_round(0.4)); 
console.log(" 0.6 -> 1 : ", bankers_round(0.6)); 
console.log(" 1.4 -> 1 : ", bankers_round(1.4)); 
console.log(" 1.6 -> 2 : ", bankers_round(1.6)); 

console.log(" 23.5 -> 24 : ", bankers_round(23.5)); 
console.log(" 24.5 -> 24 : ", bankers_round(24.5)); 
console.log(" -23.5 -> -24 : ", bankers_round(-23.5)); 
console.log(" -24.5 -> -24 : ", bankers_round(-24.5)); 
+0

注意:其中一些約定僅適用於ES6(例如:默認的parm值)。 – Spade 2016-10-12 13:25:31

0

這是不尋常的計算器在底部的答案均優於被接受。剛剛清理了@ xims解決方案,並更清晰一點:

function bankersRound(n, d=2) { 
    var x = n * Math.pow(10, d); 
    var r = Math.round(x); 
    var br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r-1) : r; 
    return br/Math.pow(10, d); 
}