每日挑战,从Javascript面试题目了解一些你可能忽略的概念 - Day3

tags: ItIron2021 Javascript

前言

前两天我们把重点放在scope以及变数的宣告与赋值上,今天我们换个口味,来看一个看似简单却极度常见的面试题目,一起来了解javascript一些奇怪的部份吧! 老样子,若你一看题目就知道今天的重点,你可以直接下拉到最後的结论:D

本日题目与解释

请问下方的程序码会有什麽输出结果?

let result = (0.1 + 0.2) === 0.3

console.log(result)

老样子来个防雷图,思考结束後再往下滑吧!

thinking-cat

同样也是个经典的面试题目,对於电脑如何处理数字的人也许已经隐隐感觉到问题在哪了,最後的输出结果为一个赤裸裸的false

false

jerry-question

我懂你的心情,且让我一步步的解释。根本的原因其实有些许复杂,有兴趣的可以自行用文末的关键字自行搜索甚至直接google此问题。简单来说Javascript遵循IEEE-754标准,以64位固定长度来表示一个数字,运算时则会根据该规范先转为二进位後再做运算,最终在这样转换过程中造成一些精度上的流失,让这样的结果出现在我们眼前。(再次强调,这只是最最最基本的说明,有兴趣深入了解的请自行google,这并不是本篇文章的重点:D)

现在你知道大概的原因了,接着你很可能就被问到该如何解决! 好问题,一般来说有以下的手段。

  • 使用套件

我真的不是在讲干话,但实务上最佳的解法就是去使用已经经过多人测试过的套件,常见的选择有math.js、big.js等,尤其在金融相关的处理上是容不得误差的,与其自己手刻一个可能有问题的function,用现成的轮子多半是比较合理的选择。

  • 部份倍化之术

是的,就是那个忍术
有深入了解实际原因时就会发现这类的情况大多会发生在小数的运算上,既然如此我先把它变成整数再运算不就好了吗? 以题目的例子来说就是这样

const computedResult = (0.1 * 10 + 0.2 * 10) / 10

console.log(computedResult === 0.3) // true
  • toPrecision

另外还有个比较少见的方法也能解决这样的问题,我们知道这样的问题是来自精度的误差,那藉由明确定义数字精度也能解决部份的情境,同样以题目的例子来看

const computedResult = parseFloat((0.1 + 0.2).toPrecision(12))

console.log(computedResult === 0.3) // true

toPrecision函数需要传入一个精度做为参数并回传处理後的字串,精度12则可以处理大多数的精度误差问题。

本日核心观念与总结

核心观念

浮点数陷阱

总结

  1. 永远不要直接用浮点数做运算,you'll be surprised and not in a good way
  2. 善用别人造好的轮子,你并不需要自己动手处理浮点数陷阱

本文章同步发布於个人部落格,有兴趣的朋友也可以来逛逛~!


<<:  @Day18 | C# WixToolset + WPF 帅到不行的安装包 [系统更新]

>>:  补充…小知识?

Day14 - Shioaji X Backtesting -回测框架搭配API历史资料

Hi,介绍了api的各种函数後,相信读者一定很好奇,有了这些资料之後要怎麽回测啊? 毕竟在开始实单做...

第19天 - 来试着做一个简易购物系统(3)建购物车的资料表、一点点SESSION

补充 今天来做购物车,昨天写 "购买,减少库存" 的时候,我其实几乎忘记有购物车...

[Day27] 测试场景与角色

今天意外顺利,把预设要做的东西都有做出来 ^_^ 今日目标 搭建测试场景 建立角色在场景上 搭建场景...

Swift纯Code之旅 Day20. 「ViewController好乱(2) - MVC画面分离」

前言 昨天已经将要用来实作MVC分离的范例完成了,那今天就马上来实作MVC分离吧! 实作 首先先创一...

EP05 - 从零开始,在 AWS 建置 Gitlab 使用 Terraform

配置 Gitlab 环境 昨天我们使用 Terraform 创建好一个给 Gitlab 使用的 EC...