GVKun编程网logo

JavaScript中的精确财务计算。什么是陷阱?(js计算金额精度)

21

在这篇文章中,我们将为您详细介绍JavaScript中的精确财务计算。什么是陷阱?的内容,并且讨论关于js计算金额精度的相关问题。此外,我们还会涉及一些关于JavaScript:两个数的精确乘法、Ja

在这篇文章中,我们将为您详细介绍JavaScript中的精确财务计算。什么是陷阱?的内容,并且讨论关于js计算金额精度的相关问题。此外,我们还会涉及一些关于JavaScript : 两个数的精确乘法、JavaScript javaScript中的Date 以及对原生javaScript的扩展、javascript – ES6中块级功能的精确语义是什么?、javascript中float类型计算的精确度问题的知识,以帮助您更全面地了解这个主题。

本文目录一览:

JavaScript中的精确财务计算。什么是陷阱?(js计算金额精度)

JavaScript中的精确财务计算。什么是陷阱?(js计算金额精度)

为了创建跨平台代码,我想用JavaScript开发一个简单的财务应用程序。所需的计算涉及复利和相对较长的十进制数。我想知道使用JavaScript进行此类数学运算时应避免的错误-
如果有可能的话!

答案1

小编典典

您可能应该将小数点后的值乘以100,并将所有货币值表示为整分。JavaScript中没有十进制数据类型-唯一的数字数据类型是浮点数。因此,通常建议将钱作为2550美分而不是25.50美元。

考虑一下JavaScript:

var result = 1.0 + 2.0;     // (result === 3.0) returns true

但:

var result = 0.1 + 0.2;     // (result === 0.3) returns false

该表达式0.1 + 0.2 === 0.3返回false,但幸运的是,浮点数的整数运算是精确的,因此可以通过缩放1来避免小数表示错误。

请注意,尽管实数集是无限的,但只能用JavaScript浮点格式精确表示实数中的有限数(准确地说是18,437,736,874,454,810,627)。因此,其他数字的表示将是实际数字2的近似值。


JavaScript : 两个数的精确乘法

JavaScript : 两个数的精确乘法

工作中要处理两个数的乘法,网上搜索了没有找到满意的答案,然后根据网上提供的思路自己实现了一个,重点满足容错的要求,就是不会轻易报错。

主要算法是记录小数点后位数的总长度,然后将两个数转变成整数后相乘,再根据小数点后位数的总长度将乘积转变成小数。

代码如下:
 

/**
 * 两个数的精确乘法
 * @param v1
 * @param v2
 *
 * 对于不能处理的问题,此方法一律返回 0
 *
 * @returns {number}
 */
function numberMultiplication (v1, v2) {
  if (isNaN(v1) || isNaN(v2)) {
    return 0
  }
  var isNegative = false;
  if ((v1 < 0 && v2 >= 0) || (v1 >=0 && v2 < 0)) {
    isNegative = true;
  }
  var f1 = '''' + Math.abs(v1),
      f2 = '''' + Math.abs(v2);
  var arr1 = f1.split(''.''),
      arr2 = f2.split(''.'');
  var f11 = arr1[0],
      f12 = 0,
      f21 = arr2[0],
      f22 = 0,
      len1 = 0,
      len2 = 0;
  if (arr1.length >= 2) {
    f12 = arr1[1];
    len1 = f12.length;
  }
  if (arr2.length >= 2) {
    f22 = arr2[1];
    len2 = f22.length;
  }
  var x1 = 0,
      x2 = 0;
  if (f11 > 0) {
    x1 = f1.replace(''.'', '''');
  } else {
    x1 = f12;
  }
  if (f21 > 0) {
    x2 = f2.replace(''.'', '''');
  } else {
    x2 = f22;
  }
  var ret = x1 * x2 / Math.pow(10, len1 + len2);
  if (isNegative) {
    return -ret;
  } else {
    return ret;
  }
}

 

JavaScript javaScript中的Date 以及对原生javaScript的扩展

JavaScript javaScript中的Date 以及对原生javaScript的扩展

原生JavaScript中的Date

JS Date 对象用于处理日期和时间。
创建 Date 对象的语法:
var myDate=new Date()
Date 对象会自动把当前日期和时间保存为其初始值。
参数形式有以下5种:  

new Date("month dd,yyyy hh:mm:ss");
new Date("month dd,yyyy");
new Date(yyyy,mth,dd,hh,mm,ss);
new Date(yyyy,mth,dd);
new Date(ms);

经测试一下几种也可以:

new Date(yyyy-MM-dd HH:mm:ss);

new Date(yyyy/MM/dd HH:mm:ss);

测试截图:


注意最后一种形式,参数表示的是需要创建的时间和GMT时间1970年1月1日之间相差的毫秒数。各种函数的含义如下:

month:用英文表示月份名称,从January到December

mth:用整数表示月份,从0-11(1月到12月)

dd:表示一个月中的第几天,从1到31

yyyy:四位数表示的年份

hh:小时数,从0(午夜)到23(晚11点)

mm:分钟数,从0到59的整数

ss:秒数,从0到59的整数

ms:毫秒数,为大于等于0的整数

如:

new Date("January 12,2006 22:19:35");

new Date("January 12,2006");

new Date(2006,0,12,22,19,35);

new Date(2006,0,12);

new Date(1137075575000);

 

Date() 返回当日的日期和时间。 
getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)。
getMonth() 从 Date 对象返回月份 (0 ~ 11)。
getFullYear() 从 Date 对象以四位数字返回年份。
getYear() 请使用 getFullYear() 方法代替。
getHours() 返回 Date 对象的小时 (0 ~ 23)。
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
getTime() 返回 1970 年 1 月 1 日至今的毫秒数。
getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差。
getUTCDate() 根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。
getUTCDay() 根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。
getUTCMonth() 根据世界时从 Date 对象返回月份 (0 ~ 11)。
getUTCFullYear() 根据世界时从 Date 对象返回四位数的年份。
getUTCHours() 根据世界时返回 Date 对象的小时 (0 ~ 23)。
getUTCMinutes() 根据世界时返回 Date 对象的分钟 (0 ~ 59)。
getUTCSeconds() 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。
getUTCMilliseconds() 根据世界时返回 Date 对象的毫秒(0 ~ 999)。
parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。
setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。
setMonth() 设置 Date 对象中月份 (0 ~ 11)。
setFullYear() 设置 Date 对象中的年份(四位数字)。
setYear() 请使用 setFullYear() 方法代替。
setHours() 设置 Date 对象中的小时 (0 ~ 23)。
setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。
setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。
setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。
setTime() 以毫秒设置 Date 对象。
setUTCDate() 根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。
setUTCMonth() 根据世界时设置 Date 对象中的月份 (0 ~ 11)。
setUTCFullYear() 根据世界时设置 Date 对象中的年份(四位数字)。
setUTCHours() 根据世界时设置 Date 对象中的小时 (0 ~ 23)。
setUTCMinutes() 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。
setUTCSeconds() 根据世界时设置 Date 对象中的秒钟 (0 ~ 59)。
setUTCMilliseconds() 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。
toSource() 返回该对象的源代码。
toString() 把 Date 对象转换为字符串。
toTimeString() 把 Date 对象的时间部分转换为字符串。
toDateString() 把 Date 对象的日期部分转换为字符串。
toGMTString() 请使用 toUTCString() 方法代替。
toUTCString() 根据世界时,把 Date 对象转换为字符串。
toLocaleString() 根据本地时间格式,把 Date 对象转换为字符串。
toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部分转换为字符串。
toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部分转换为字符串。
UTC() 根据世界时返回 1997 年 1 月 1 日 到指定日期的毫秒数。
valueOf() 返回 Date 对象的原始值。



对JavaScript中的Date格式化的扩展

方法一:这个很不错,好像是 csdn 的 Meizz 写的: 

// 对Date的扩展,将 Date 转化为指定格式的String
  • // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
  • // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
  • // 例子:
  • // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
  • // (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
  • Date.prototype.Format = function(fmt)
  • { //author: meizz
  • var o = {
  • "M+" : this.getMonth()+1, //月份
  • "d+" : this.getDate(), //日
  • "H+" : this.getHours(), //小时
  • "m+" : this.getMinutes(), //分
  • "s+" : this.getSeconds(), //秒
  • "q+" : Math.floor((this.getMonth()+3)/3), //季度
  • "S" : this.getMilliseconds() //毫秒
  • };
  • if(/(y+)/.test(fmt))
  • fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
  • for(var k in o)
  • if(new RegExp("("+ k +")").test(fmt))
  • fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
  • return fmt;
  • };

  • 调用方法:

    [javascript] view plain copy
    1. var time1 = new Date().Format("yyyy-MM-dd HH:mm:ss");     
    2.   
    3. var time2 = new Date().Format("yyyy-MM-dd");    

     



    方法二:

    [javascript]  view plain  copy
    1. <mce:script language="javascript" type="text/javascript"><!--  
    2.         
    3. /**       
    4.  * 对Date的扩展,将 Date 转化为指定格式的String       
    5.  * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q) 可以用 1-2 个占位符       
    6.  * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)       
    7.  * eg:       
    8.  * (new Date()).pattern("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423       
    9.  * (new Date()).pattern("yyyy-MM-dd E HH:mm:ss") ==> 2009-03-10 二 20:09:04       
    10.  * (new Date()).pattern("yyyy-MM-dd EE hh:mm:ss") ==> 2009-03-10 周二 08:09:04       
    11.  * (new Date()).pattern("yyyy-MM-dd EEE hh:mm:ss") ==> 2009-03-10 星期二 08:09:04       
    12.  * (new Date()).pattern("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18       
    13.  */          
    14. Date.prototype.pattern=function(fmt) {           
    15.     var o = {           
    16.     "M+" : this.getMonth()+1, //月份           
    17.     "d+" : this.getDate(), //日           
    18.     "h+" : this.getHours()%12 == 0 ? 12 : this.getHours()%12, //小时           
    19.     "H+" : this.getHours(), //小时           
    20.     "m+" : this.getMinutes(), //分           
    21.     "s+" : this.getSeconds(), //秒           
    22.     "q+" : Math.floor((this.getMonth()+3)/3), //季度           
    23.     "S" : this.getMilliseconds() //毫秒           
    24.     };           
    25.     var week = {           
    26.     "0" : "/u65e5",           
    27.     "1" : "/u4e00",           
    28.     "2" : "/u4e8c",           
    29.     "3" : "/u4e09",           
    30.     "4" : "/u56db",           
    31.     "5" : "/u4e94",           
    32.     "6" : "/u516d"          
    33.     };           
    34.     if(/(y+)/.test(fmt)){           
    35.         fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));           
    36.     }           
    37.     if(/(E+)/.test(fmt)){           
    38.         fmt=fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "/u661f/u671f" : "/u5468") : "")+week[this.getDay()+""]);           
    39.     }           
    40.     for(var k in o){           
    41.         if(new RegExp("("+ k +")").test(fmt)){           
    42.             fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));           
    43.         }           
    44.     }           
    45.     return fmt;           
    46. }         
    47.        
    48. var date = new Date();        
    49. window.alert(date.pattern("yyyy-MM-dd hh:mm:ss"));  
    50. // --></mce:script>      

     


    方法三:

    [javascript]  view plain  copy
    1. Date.prototype.format = function(mask) {        
    2.        
    3.     var d = this;        
    4.        
    5.     var zeroize = function (value, length) {        
    6.        
    7.         if (!length) length = 2;        
    8.        
    9.         value = String(value);        
    10.        
    11.         for (var i = 0, zeros = ''; i < (length - value.length); i++) {        
    12.        
    13.             zeros += '0';        
    14.        
    15.         }        
    16.        
    17.         return zeros + value;        
    18.        
    19.     };          
    20.        
    21.     return mask.replace(/"[^"]*"|'[^']*'|/b(?:d{1,4}|m{1,4}|yy(?:yy)?|([hHMstT])/1?|[lLZ])/b/g, function($0) {        
    22.        
    23.         switch($0) {        
    24.        
    25.             case 'd':   return d.getDate();        
    26.        
    27.             case 'dd':  return zeroize(d.getDate());        
    28.        
    29.             case 'ddd'return ['Sun','Mon','Tue','Wed','Thr','Fri','Sat'][d.getDay()];        
    30.        
    31.             case 'dddd':    return ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'][d.getDay()];        
    32.        
    33.             case 'M':   return d.getMonth() + 1;        
    34.        
    35.             case 'MM':  return zeroize(d.getMonth() + 1);        
    36.        
    37.             case 'MMM'return ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][d.getMonth()];        
    38.        
    39.             case 'MMMM':    return ['January','February','March','April','May','June','July','August','September','October','November','December'][d.getMonth()];        
    40.        
    41.             case 'yy':  return String(d.getFullYear()).substr(2);        
    42.        
    43.             case 'yyyy':    return d.getFullYear();        
    44.        
    45.             case 'h':   return d.getHours() % 12 || 12;        
    46.        
    47.             case 'hh':  return zeroize(d.getHours() % 12 || 12);        
    48.        
    49.             case 'H':   return d.getHours();        
    50.        
    51.             case 'HH':  return zeroize(d.getHours());        
    52.        
    53.             case 'm':   return d.getMinutes();        
    54.        
    55.             case 'mm':  return zeroize(d.getMinutes());        
    56.        
    57.             case 's':   return d.getSeconds();        
    58.        
    59.             case 'ss':  return zeroize(d.getSeconds());        
    60.        
    61.             case 'l':   return zeroize(d.getMilliseconds(), 3);        
    62.        
    63.             case 'L':   var m = d.getMilliseconds();        
    64.        
    65.                     if (m > 99) m = Math.round(m / 10);        
    66.        
    67.                     return zeroize(m);        
    68.        
    69.             case 'tt':  return d.getHours() < 12 ? 'am' : 'pm';        
    70.        
    71.             case 'TT':  return d.getHours() < 12 ? 'AM' : 'PM';        
    72.        
    73.             case 'Z':   return d.toUTCString().match(/[A-Z]+$/);        
    74.        
    75.             // Return quoted strings with the surrounding quotes removed        
    76.        
    77.             default:    return $0.substr(1, $0.length - 2);        
    78.        
    79.         }        
    80.        
    81.     });        
    82.        
    83. };      

    javascript – ES6中块级功能的精确语义是什么?

    javascript – ES6中块级功能的精确语义是什么?

    我试图通过阅读原始规范来围绕ES6中的新标准化块级功能.我表面上的理解是:

    > ES6中允许使用块级函数声明.
    他们提升到块的顶部.
    >在严格模式下,它们在包含块外不可见.

    然而,由于这些语义的一部分被指定为“可选”且仅对网络浏览器(Annex B)是强制性的,这一点更为复杂.所以我想要下列表格填写:

                                                 |  Visible outside of block?  |  Hoisted? Up to which point?  |   "TDZ"? |
    ------------------------------------------------------------------------------------------------------------------------
    |   Non-strict mode,no "web extensions"   |                             |                               |          |
    |   Strict mode,no "web extensions"   |                             |                               |          |
    |   Non strict mode,with "web extensions  |                             |                               |          |
    |   Strict mode,with "web extensions" |                             |                               |          |
    

    在这种情况下,我还不清楚“严格模式”是什么意思.作为函数声明的运行时执行的一些额外步骤的一部分,这种区别似乎在Annex B3.3中被引入:

    1. If strict is false,then
    ...

    然而,据我所见,strict是指函数对象的[[Strict]]内部插槽.这是否意味着:

    // Non-strict surrounding code
    
    {
        function foo() {"use strict";}
    }

    在上表中应该被认为是“严格模式”?然而,这与我的初步直觉相矛盾.

    请记住,我对ES6规范本身大多感兴趣,不管实际的实现不一致.

    解决方法

    As far as I can see,strict refers to the [[Strict]] internal slot of the function object.

    不,是的.它指的是发生包含函数声明的块的函数(or script)的严格性.不是要声明的(或不是)的功能的严格性.

    “Web扩展”只适用于粗糙(非严格)的代码,只有当函数语句的外观是“一致的” – 就是说,例如,如果它的名称不与正式参数或词汇冲突声明变量.

    请注意,没有Web兼容性语义的严格和粗糙的代码之间没有区别.在纯ES6中,块中的函数声明只有一种行为.

    所以我们基本上都有

    |      web-compat               pure
    -----------------+---------------------------------------------
    strict mode ES6  |  block hoisting            block hoisting
    sloppy mode ES6  |  it's complicated ¹        block hoisting
    strict mode ES5  |  undefined behavior ²      SyntaxError
    sloppy mode ES5  |  undefined behavior ³      SyntaxError

    1:见下文.要求提供警告.
    2:通常,会抛出一个SyntaxError
    3:ES5.1 §12会议记录“实施中的重大和不可调和的变化”(如these).建议使用警告.

    那么现在,具有Web兼容性的ES6实现如何在具有传统语义的马尔可夫模式函数中的块中执行函数声明?
    首先,纯粹的语义仍然适用.也就是说,函数声明被提升到词汇块的顶部.
    然而,还有一个var声明被提升到封闭函数的顶部.
    并且当函数声明被评估时(在块中,好像像语句一样被满足),函数对象被分配给该函数范围的变量.

    这通过代码更好地解释:

    function enclosing(…) {
        …
        {
             …
             function compat(…) { … }
             …
        }
        …
    }

    工作方式相同

    function enclosing(…) {
        var compat₀ = undefined; // function-scoped
        …
        {
             let compat₁ = function compat(…) { … }; // block-scoped
             …
             compat₀ = compat₁;
             …
        }
        …
    }

    是的,这有点混乱,有两个不同的绑定(用下标0和1表示),名称相同.所以现在我可以简洁地回答你的问题:

    Visible outside of block?

    是的,像一个var.但是,第二个绑定只能在块内部显示.

    Hoisted?

    是的 – 两次

    Up to which point?

    两个函数(不是初始化为undefined)和块(用函数对象初始化).

    “TDZ”?

    不是在引用引用时引用的词法声明变量(let / const / class)的时间死区的意义上.但是在执行body之前遇到函数声明,函数范围的变量是未定义的(尤其是在块之前),如果你尝试调用它,你也会得到异常.

    javascript中float类型计算的精确度问题

    javascript中float类型计算的精确度问题

    在平时的使用过程中,发现使用float类型在进行计算的时候,有些数字在进行计算后,小数点后面的位数明显变多,并且最后一位不为零,和正常的计算结果产生了误差。首先看一下我的代码。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title>求和</title>
    		
    	</head>
    	<body>
    		<input type="text" id="add1" value="" />
    		<input type="text" id="add2" value="" />
    		<input type="button" id="add3" value="add" onclick="add()"/>
    		<script type="text/javascript">
    			function add(){
    				var a1 = document.getElementById(''add1'').value;
    				var a2 = document.getElementById(''add2'').value;
    				if(isNaN(a1)||isNaN(a2)){
    					alert(''非法的数据类型'')//非法数据类型报错
    				}
    				else{
    					var num = parseFloat(a1)+parseFloat(a2);//相加
    					alert(num);	//弹出结果
    				}
    				
    			}
    		</script>
    	</body>
    </html>
    运行代码可以发现,有一部分数字的计算是没有问题的,但是当我输入1.1和2.2然后相加的时候发现结果变成了3.30000000003(不知道几个0,随便写了几个)。然后我发现问题后在百度搜索答案。

    找到一段解释如下,但是个人觉得解释的不是很好。

    (非原创)在JavsScript中,变量在存储时并不区分number和float类型,而是统一按float存储。而javascript使用IEEE 754-2008 标准定义的64bit浮点格式存储number,按照IEEE 754的定义:decimal64对应的整形部分长度为10,小数部分长度为16,所以默认的计算结果为“7.0000000000000001”,如最后一个小数为0,则取1作为有效数字标志。


    解决方法:1、在计算结果后限制小数点后的位数,以我的代码为例。

    var num = (parseFloat(a1)+parseFloat(a2)).toFixed(5);//保留小数点后五位

    2、重写浮点计算的函数

    //加法函数,用来得到精确的加法结果
    //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
    //调用:accAdd(arg1,arg2)
    //返回值:arg1加上arg2的精确结果
    function accAdd(arg1, arg2) {
        var r1, r2, m;
        try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 }
        try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 }
        m = Math.pow(10, Math.max(r1, r2))
        return (arg1 * m + arg2 * m) / m
    }







    我们今天的关于JavaScript中的精确财务计算。什么是陷阱?js计算金额精度的分享已经告一段落,感谢您的关注,如果您想了解更多关于JavaScript : 两个数的精确乘法、JavaScript javaScript中的Date 以及对原生javaScript的扩展、javascript – ES6中块级功能的精确语义是什么?、javascript中float类型计算的精确度问题的相关信息,请在本站查询。

    本文标签:

    上一篇使用Javascript数组计算集合差异的最快或最优雅的方法是什么?(js 数组差集)

    下一篇在JavaScript中计算字符串值,而不使用eval(javascript计算字符串的长度)