JS浮點(diǎn)數(shù)字操作插件floatOPS.js

/**

* floatOPS 包含加減乘除四個(gè)方法,能確保浮點(diǎn)數(shù)運(yùn)算不丟失精度

*

* 我們知道計(jì)算機(jī)編程語言里浮點(diǎn)數(shù)計(jì)算會(huì)存在精度丟失問題(或稱舍入誤差),其根本原因是二進(jìn)制和實(shí)現(xiàn)位數(shù)限制有些數(shù)無法有限表示

* 以下是十進(jìn)制小數(shù)對(duì)應(yīng)的二進(jìn)制表示

*? ? ? 0.1 >> 0.0001 1001 1001 1001…(1001無限循環(huán))

*? ? ? 0.2 >> 0.0011 0011 0011 0011…(0011無限循環(huán))

* 計(jì)算機(jī)里每種數(shù)據(jù)類型的存儲(chǔ)是一個(gè)有限寬度,比如 JavaScript 使用 64 位存儲(chǔ)數(shù)字類型,因此超出的會(huì)舍去。舍去的部分就是精度丟失的部分。

*

* ** method **

*? add / subtract / multiply /divide

*

* ** explame **

*? 0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004)

*? 0.2 + 0.4 == 0.6000000000000001? (多了 0.0000000000001)

*? 19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002)

*

* floatOPS.add(0.1, 0.2) >> 0.3

* floatOPS.multiply(19.9, 100) >> 1990

*

*/

var floatOPS = function () {

? ? /*

? ? * 判斷obj是否為一個(gè)整數(shù)

? ? */

? ? function isInteger(obj) {

? ? ? ? return Math.floor(obj) === obj

? ? }

? ? /*

? ? * 將一個(gè)浮點(diǎn)數(shù)轉(zhuǎn)成整數(shù),返回整數(shù)和倍數(shù)。如 3.14 >> 314,倍數(shù)是 100

? ? * @param floatNum {number} 小數(shù)

? ? * @return {object}

? ? *? {times:100, num: 314}

? ? */

? ? function toInteger(floatNum) {

? ? ? ? var ret = { times: 1, num: 0 }

? ? ? ? var isNegative = floatNum < 0

? ? ? ? if (isInteger(floatNum)) {

? ? ? ? ? ? ret.num = floatNum

? ? ? ? ? ? return ret

? ? ? ? }

? ? ? ? var strfi = floatNum + ''

? ? ? ? var dotPos = strfi.indexOf('.')

? ? ? ? var len = strfi.substr(dotPos + 1).length

? ? ? ? var times = Math.pow(10, len)

? ? ? ? var intNum = parseInt(Math.abs(floatNum) * times + 0.5, 10)

? ? ? ? ret.times = times

? ? ? ? if (isNegative) {

? ? ? ? ? ? intNum = -intNum

? ? ? ? }

? ? ? ? ret.num = intNum

? ? ? ? return ret

? ? }

? ? /*

? ? * 核心方法,實(shí)現(xiàn)加減乘除運(yùn)算,確保不丟失精度

? ? * 思路:把小數(shù)放大為整數(shù)(乘),進(jìn)行算術(shù)運(yùn)算,再縮小為小數(shù)(除)

? ? *

? ? * @param a {number} 運(yùn)算數(shù)1

? ? * @param b {number} 運(yùn)算數(shù)2

? ? * @param digits {number} 精度,保留的小數(shù)點(diǎn)數(shù),比如 2, 即保留為兩位小數(shù)

? ? * @param op {string} 運(yùn)算類型,有加減乘除(add/subtract/multiply/divide)

? ? *

? ? */

? ? function operation(a, b, digits, op) {

? ? ? ? var o1 = toInteger(a)

? ? ? ? var o2 = toInteger(b)

? ? ? ? var n1 = o1.num

? ? ? ? var n2 = o2.num

? ? ? ? var t1 = o1.times

? ? ? ? var t2 = o2.times

? ? ? ? var max = t1 > t2 ? t1 : t2

? ? ? ? var result = null

? ? ? ? switch (op) {

? ? ? ? ? ? case 'add':

? ? ? ? ? ? ? ? if (t1 === t2) { // 兩個(gè)小數(shù)位數(shù)相同

? ? ? ? ? ? ? ? ? ? result = n1 + n2

? ? ? ? ? ? ? ? } else if (t1 > t2) { // o1 小數(shù)位 大于 o2

? ? ? ? ? ? ? ? ? ? result = n1 + n2 * (t1 / t2)

? ? ? ? ? ? ? ? } else { // o1 小數(shù)位 小于 o2

? ? ? ? ? ? ? ? ? ? result = n1 * (t2 / t1) + n2

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return result / max

? ? ? ? ? ? case 'subtract':

? ? ? ? ? ? ? ? if (t1 === t2) {

? ? ? ? ? ? ? ? ? ? result = n1 - n2

? ? ? ? ? ? ? ? } else if (t1 > t2) {

? ? ? ? ? ? ? ? ? ? result = n1 - n2 * (t1 / t2)

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? result = n1 * (t2 / t1) - n2

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return result / max

? ? ? ? ? ? case 'multiply':

? ? ? ? ? ? ? ? result = (n1 * n2) / (t1 * t2)

? ? ? ? ? ? ? ? return result

? ? ? ? ? ? case 'divide':

? ? ? ? ? ? ? ? result = (n1 / n2) * (t2 / t1)

? ? ? ? ? ? ? ? return result

? ? ? ? }

? ? }

? ? // 加減乘除的四個(gè)接口

? ? function add(a, b, digits) {

? ? ? ? return operation(a, b, digits, 'add')

? ? }

? ? function subtract(a, b, digits) {

? ? ? ? return operation(a, b, digits, 'subtract')

? ? }

? ? function multiply(a, b, digits) {

? ? ? ? return operation(a, b, digits, 'multiply')

? ? }

? ? function divide(a, b, digits) {

? ? ? ? return operation(a, b, digits, 'divide')

? ? }

? ? // exports

? ? return {

? ? ? ? add: add,

? ? ? ? subtract: subtract,

? ? ? ? multiply: multiply,

? ? ? ? divide: divide

? ? }

}();

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容