Will someone ever be faced with wrong results of simple arithmetic operations on floating point numbers if...
Note: numbers which I'm talking about are currency, thus don't have more than two digits in fractional part.
I've tested 4 libraries (Decimal.js, Numeral.js, Big.js and Math.js) and a simple plain javascript implementation function (which uses Math.round
for cutting off fractional part) with two arithmetic operations:
- 0.55 * 100 => 55 // but it gives 55.00000000000001
- 0.2 + 0.1 => 0.3 // but it gives 0.30000000000000004
Test script (node v10.4.1, Ubuntu 16.04LTS)
const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')
const assert = require('assert')
function roundMultiply () {
return Math.round(0.55 * 100)
}
function roundAdd () {
return Math.round((0.2 + 0.1) * 100) / 100
}
function decimalMultiply () {
return new Decimal(0.55).mul(new Decimal(100))
}
function decimalAdd () {
return new Decimal(0.2).add(new Decimal(0.1))
}
function numeralMultiply () {
return numeral(0.55).multiply(100).value()
}
function numeralAdd () {
return numeral(0.2).add(0.1).value()
}
function bigJsMultiply () {
return +(new Big(0.55).times(100))
}
function bigJsAdd () {
return +(new Big(0.2).add(0.1))
}
function mathJsMultiply () {
return math.number(math.multiply(math.fraction(0.55), 100))
}
function mathJsAdd () {
return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}
function test (fun, funName) {
console.time(funName)
for (let i = 0; i < 100000; i++) {
fun()
}
console.timeEnd(funName)
}
console.log('test multiplication results...')
assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')
console.log('test multiplication performance...')
test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')
console.log('test adding results...')
assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')
console.log('test adding performance...')
test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')
Results
roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms
roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms
As you can see, roundAdd
and roundMultiply
are far ahead of all other functions.
My main question: are there operands having at most two digits in fractional part and such, which, when peforming simple arithmetic operations (+, -, *, /) with them, whould give incorrect result when using Math.round
? Because I can't see any reason why would I need to use any of those (or other libraries) taking into account their performance.
javascript math floating-point
add a comment |
Note: numbers which I'm talking about are currency, thus don't have more than two digits in fractional part.
I've tested 4 libraries (Decimal.js, Numeral.js, Big.js and Math.js) and a simple plain javascript implementation function (which uses Math.round
for cutting off fractional part) with two arithmetic operations:
- 0.55 * 100 => 55 // but it gives 55.00000000000001
- 0.2 + 0.1 => 0.3 // but it gives 0.30000000000000004
Test script (node v10.4.1, Ubuntu 16.04LTS)
const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')
const assert = require('assert')
function roundMultiply () {
return Math.round(0.55 * 100)
}
function roundAdd () {
return Math.round((0.2 + 0.1) * 100) / 100
}
function decimalMultiply () {
return new Decimal(0.55).mul(new Decimal(100))
}
function decimalAdd () {
return new Decimal(0.2).add(new Decimal(0.1))
}
function numeralMultiply () {
return numeral(0.55).multiply(100).value()
}
function numeralAdd () {
return numeral(0.2).add(0.1).value()
}
function bigJsMultiply () {
return +(new Big(0.55).times(100))
}
function bigJsAdd () {
return +(new Big(0.2).add(0.1))
}
function mathJsMultiply () {
return math.number(math.multiply(math.fraction(0.55), 100))
}
function mathJsAdd () {
return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}
function test (fun, funName) {
console.time(funName)
for (let i = 0; i < 100000; i++) {
fun()
}
console.timeEnd(funName)
}
console.log('test multiplication results...')
assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')
console.log('test multiplication performance...')
test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')
console.log('test adding results...')
assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')
console.log('test adding performance...')
test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')
Results
roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms
roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms
As you can see, roundAdd
and roundMultiply
are far ahead of all other functions.
My main question: are there operands having at most two digits in fractional part and such, which, when peforming simple arithmetic operations (+, -, *, /) with them, whould give incorrect result when using Math.round
? Because I can't see any reason why would I need to use any of those (or other libraries) taking into account their performance.
javascript math floating-point
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
4
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because ofMath.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks
– gumkins
Nov 13 '18 at 18:54
add a comment |
Note: numbers which I'm talking about are currency, thus don't have more than two digits in fractional part.
I've tested 4 libraries (Decimal.js, Numeral.js, Big.js and Math.js) and a simple plain javascript implementation function (which uses Math.round
for cutting off fractional part) with two arithmetic operations:
- 0.55 * 100 => 55 // but it gives 55.00000000000001
- 0.2 + 0.1 => 0.3 // but it gives 0.30000000000000004
Test script (node v10.4.1, Ubuntu 16.04LTS)
const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')
const assert = require('assert')
function roundMultiply () {
return Math.round(0.55 * 100)
}
function roundAdd () {
return Math.round((0.2 + 0.1) * 100) / 100
}
function decimalMultiply () {
return new Decimal(0.55).mul(new Decimal(100))
}
function decimalAdd () {
return new Decimal(0.2).add(new Decimal(0.1))
}
function numeralMultiply () {
return numeral(0.55).multiply(100).value()
}
function numeralAdd () {
return numeral(0.2).add(0.1).value()
}
function bigJsMultiply () {
return +(new Big(0.55).times(100))
}
function bigJsAdd () {
return +(new Big(0.2).add(0.1))
}
function mathJsMultiply () {
return math.number(math.multiply(math.fraction(0.55), 100))
}
function mathJsAdd () {
return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}
function test (fun, funName) {
console.time(funName)
for (let i = 0; i < 100000; i++) {
fun()
}
console.timeEnd(funName)
}
console.log('test multiplication results...')
assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')
console.log('test multiplication performance...')
test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')
console.log('test adding results...')
assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')
console.log('test adding performance...')
test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')
Results
roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms
roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms
As you can see, roundAdd
and roundMultiply
are far ahead of all other functions.
My main question: are there operands having at most two digits in fractional part and such, which, when peforming simple arithmetic operations (+, -, *, /) with them, whould give incorrect result when using Math.round
? Because I can't see any reason why would I need to use any of those (or other libraries) taking into account their performance.
javascript math floating-point
Note: numbers which I'm talking about are currency, thus don't have more than two digits in fractional part.
I've tested 4 libraries (Decimal.js, Numeral.js, Big.js and Math.js) and a simple plain javascript implementation function (which uses Math.round
for cutting off fractional part) with two arithmetic operations:
- 0.55 * 100 => 55 // but it gives 55.00000000000001
- 0.2 + 0.1 => 0.3 // but it gives 0.30000000000000004
Test script (node v10.4.1, Ubuntu 16.04LTS)
const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')
const assert = require('assert')
function roundMultiply () {
return Math.round(0.55 * 100)
}
function roundAdd () {
return Math.round((0.2 + 0.1) * 100) / 100
}
function decimalMultiply () {
return new Decimal(0.55).mul(new Decimal(100))
}
function decimalAdd () {
return new Decimal(0.2).add(new Decimal(0.1))
}
function numeralMultiply () {
return numeral(0.55).multiply(100).value()
}
function numeralAdd () {
return numeral(0.2).add(0.1).value()
}
function bigJsMultiply () {
return +(new Big(0.55).times(100))
}
function bigJsAdd () {
return +(new Big(0.2).add(0.1))
}
function mathJsMultiply () {
return math.number(math.multiply(math.fraction(0.55), 100))
}
function mathJsAdd () {
return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}
function test (fun, funName) {
console.time(funName)
for (let i = 0; i < 100000; i++) {
fun()
}
console.timeEnd(funName)
}
console.log('test multiplication results...')
assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')
console.log('test multiplication performance...')
test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')
console.log('test adding results...')
assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')
console.log('test adding performance...')
test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')
Results
roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms
roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms
As you can see, roundAdd
and roundMultiply
are far ahead of all other functions.
My main question: are there operands having at most two digits in fractional part and such, which, when peforming simple arithmetic operations (+, -, *, /) with them, whould give incorrect result when using Math.round
? Because I can't see any reason why would I need to use any of those (or other libraries) taking into account their performance.
javascript math floating-point
javascript math floating-point
edited Nov 13 '18 at 19:04
gumkins
asked Nov 13 '18 at 13:33
gumkinsgumkins
2,87142945
2,87142945
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
4
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because ofMath.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks
– gumkins
Nov 13 '18 at 18:54
add a comment |
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
4
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because ofMath.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks
– gumkins
Nov 13 '18 at 18:54
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
4
4
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because of
Math.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks– gumkins
Nov 13 '18 at 18:54
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because of
Math.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks– gumkins
Nov 13 '18 at 18:54
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282190%2fwill-someone-ever-be-faced-with-wrong-results-of-simple-arithmetic-operations-on%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282190%2fwill-someone-ever-be-faced-with-wrong-results-of-simple-arithmetic-operations-on%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Possible duplicate of Is floating point math broken?
– duffymo
Nov 13 '18 at 15:04
4
@duffymo Come on, guys, this site becomes useless because each question is similar to some another question or contains similar keys in its subject or description. Do you really think that because that question is also about binary arithmetic inaccuracy there is no doubt that it contains answers will I ever be faced with errors because of
Math.round
usage instead of special JS library? Well, may be you think my question has not the best subject, in that case can you please suggest better one or what I should improve in it? Thanks– gumkins
Nov 13 '18 at 18:54