小学数学老师教过我们,0.1 + 0.2 = 0.3,但是为什么在我们在浏览器的控制台中输出却是0.30000000000000004?
除了加法有这个奇怪的现象,带小数点的减法和乘除计算也会得出意料之外的结果
console.log(0.3 - 0.1) // 0.19999999999999998
console.log(0.1 * 0.2) // 0.020000000000000004
console.log(0.3 / 0.1) // 2.9999999999999996
我们都知道计算机时是通过二进制来进行计算的,即 0 和 1
就拿 0.1 + 0.2 来说,0.1表示为0.0001100110011001...,而0.2表示为0.0011001100110011...
而在二进制中 1 + 1 = 10,所以 0.1 + 0.2 = 0.0100110011001100...
转成10进制就近似表示为 0.30000000000000004
简单来说就是,浮点数转成二进制时丢失了精度,因此在二进制计算完再转回十进制时可能会和理论结果不同
对于浮点数的四则运算,许多编程语言都会有理论值和实际值不同的问题。例如Java中也会出现类似的问题,但是Java中可以使用java.math.BigDecimal类来避免这种情况
可是JS是弱类型的语言,作者Brendan Eich自述10天内开发出JS语言,一开始设计的时候就没有对浮点数计算有个处理的好方法
那么在日常开发的前端项目中我们可以怎么解决嘞?
可以控制小数点后几位,如果为空的话会用0补充,返回一个字符串
> 0.123.toFixed(2) // '0.12'
缺点:
// 在chrome控制台中
> 1.014.toFixed(2) // '1.01'
> 1.215.toFixed(2) // '1.22'
> 1.105.toFixed(2) // '1.10'
> 1.115.toFixed(2) // '1.11'
把需要计算的数字乘以10的n次方,让数值都变为整数,计算完后再除以10的n次方,这样就不会出现浮点数精度丢失问题
> (0.1 * 10 + 0.2 *10) / 10 // 0.3
我们可以将它封装成一个函数
mathFloat = function (float, digit) {
const math = Math.pow(10, digit);
return parseInt(float * math, 10) / math;
}
mathFloat(0.1 + 0.2, 3) // 0.3
缺点:
function mathPlus(arg1, arg2) {
let r1, r2, m;
try {
r1 = arg1.toString().split(".")[1].length; // 获取小数点后字符长度
} catch (error) {
r1 = 0; // 为整数状态,r1赋0
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (error) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); // 确保所有参数都为整数
return (arg1 * m + arg2 * m) / m;
}
> mathPlus(0.1, 0.2); // 0.3
> mathPlus(1, 2); // 3
function mathSubtract(arg1, arg2) {
let r1, r2, m;
try {
r1 = arg1.toString().split(".")[1].length;
} catch (error) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (error) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return ((arg1 * m - arg2 * m) / m);
}
> mathSubtract(0.3, 0.1); // 0.2
> mathSubtract(3, 1); // 2
function mathMultiply(arg1, arg2) {
let m = 0;
let s1 = arg1.toString();
let s2 = arg2.toString();
try {
m += s1.split('.')[1].length; // 小数相乘,小数点后个数相加
} catch (e) {}
try {
m += s2.split('.')[1].length;
} catch (e) {}
return (
(Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) /
Math.pow(10, m)
);
}
> mathMultiply(0.1, 0.2); // 0.02
> mathMultiply(1, 2); // 2
function mathDivide(arg1, arg2) {
let m1 = 0;
let m2 = 0;
let n1 = 0;
let n2 = 0;
try {
m1 = arg1.toString().split('.')[1].length;
} catch (e) {}
try {
m2 = arg2.toString().split('.')[1].length;
} catch (e) {}
n1 = Number(arg1.toString().replace('.', ''));
n2 = Number(arg2.toString().replace('.', ''));
/**
* 将除法转换成乘法
* 乘以它们的小数点后个数差
*/
return mathMultiply(n1 / n2, Math.pow(10, m2 - m1));
}
// > 0.2 / 0.03 => 6.666666666666667
> mathDivide(0.2, 0.03); // 6.666666666666665
> mathDivide(0.3, 0.1); // 3
> mathDivide(3, 1); // 3
站在前人的肩膀上,可以前进的更快。下面这些成熟的库封装了很多实用的函数,虽然部分函数可能永远不会用到
介绍:功能强大,内置大量函数,体积较大
Github地址:https://github.com/josdejong/mathjs
star: 12.2k+
介绍:支持三角函数等,并支持非整数幂
Github地址:https://github.com/MikeMcl/decimal.js
star: 4.8k+
介绍:体积6k,提供了CDN
Github地址:https://github.com/MikeMcl/big.js
star: 3.9k+
介绍:体积很小,只有1k左右
Github地址:https://github.com/nefe/number-precision
star: 3.4k+
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
所以我开始关注ruby,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出
给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R
我在我的Rails3示例应用程序上使用CarrierWave。我想验证远程位置上传,因此当用户提交无效URL(空白或非图像)时,我不会收到标准错误异常:CarrierWave::DownloadErrorinImageController#createtryingtodownloadafilewhichisnotservedoverHTTP这是我的模型:classPaintingtrue,:length=>{:minimum=>5,:maximum=>100}validates:image,:presence=>trueend这是我的Controller:classPaintingsC
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
我正在研究使用EventMachine支持的twitter-streamrubygem来跟踪和捕获推文。我对整个事件编程有点陌生。我如何判断我在事件循环中所做的任何处理是否导致我落后?有没有简单的检查方法? 最佳答案 您可以通过使用周期性计时器并打印出耗时来确定延迟。如果您使用的是1秒的计时器,您应该已经过了大约1秒,如果它更长,您就知道您正在减慢react器的速度。@last=Time.now.to_fEM.add_periodic_timer(1)doputs"LATENCY:#{Time.now.to_f-@last}"@
啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组
在Ruby中有运算符(operator)。在API中,他们没有命名它的名字,只是:Theclassmustdefinetheoperator...Comparableusestoimplementtheconventionalcomparison......theobjectsinthecollectionmustalsoimplementameaningfuloperator...它叫什么名字? 最佳答案 参见上面的@Tony。然而,它也被称为(俚语)“宇宙飞船运算符(operator)”。
这里还有一个新手问题:require'tasks/rails'我在每个Rails项目的根路径中的Rakefile中看到了这一行。我猜这行用于要求vendor/rails/railties/lib/tasks/rails.rb加载所有rake任务:$VERBOSE=nil#LoadRailsrakefileextensionsDir["#{File.dirname(__FILE__)}/*.rake"].each{|ext|loadext}#LoadanycustomrakefileextensionsDir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].so
电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑