🔥

[javascript] "Math.round()" or "Number.prototype.toFixed()"

2024/07/26に公開
  • note: updated at 7/26
    I noticed that, when debugging, we shouldn't format the number or string.
    I wrote more details in the "Bug Fix" part in this post.

Intro.

When I rounded a negative number by "Math.round()" or "Number.prototype.toFixed()", I noticed a little difference.

"Math.round()" converted -12.5 into -12.0 and -12.6 into -13.0 .

  • -12.5 -> -12.0
  • -12.6 -> -13.0

"toFixed()" converted -12.4 into -12.0 and -12.5 into -13.0 .

  • -12.4 -> -12.0
  • -12.5 -> -13.0

I feel that "Math.round()" seems correct mathematically.

List

Here is the list of rounding numbers(12 ~ 13 and -13 ~ -12)

  • using "Math.round()"
positive number negative number
Math.round() before: 13 => after: 13 Math.round() before: -12 => after: -12
Math.round() before: 12.9 => after: 13 Math.round() before: -12.1 => after: -12
Math.round() before: 12.8 => after: 13 Math.round() before: -12.2 => after: -12
Math.round() before: 12.7 => after: 13 Math.round() before: -12.3 => after: -12
Math.round() before: 12.6 => after: 13 Math.round() before: -12.4 => after: -12
Math.round() before: 12.5 => after: 13 Math.round() before: -12.5 => after: -12
Math.round() before: 12.4 => after: 12 Math.round() before: -12.6 => after: -13
Math.round() before: 12.3 => after: 12 Math.round() before: -12.7 => after: -13
Math.round() before: 12.2 => after: 12 Math.round() before: -12.8 => after: -13
Math.round() before: 12.1 => after: 12 Math.round() before: -12.9 => after: -13
Math.round() before: 12 => after: 12 Math.round() before: -13 => after: -13
  • using ".toFixed()"
positive number negative number
.toFixed() before: 13 => after: 13 .toFixed() before: -12 => after: -12
.toFixed() before: 12.9 => after: 13 .toFixed() before: -12.1 => after: -12
.toFixed() before: 12.8 => after: 13 .toFixed() before: -12.2 => after: -12
.toFixed() before: 12.7 => after: 13 .toFixed() before: -12.3 => after: -12
.toFixed() before: 12.6 => after: 13 .toFixed() before: -12.4 => after: -12
.toFixed() before: 12.5 => after: 13 .toFixed() before: -12.5 => after: -13
.toFixed() before: 12.4 => after: 12 .toFixed() before: -12.6 => after: -13
.toFixed() before: 12.3 => after: 12 .toFixed() before: -12.7 => after: -13
.toFixed() before: 12.2 => after: 12 .toFixed() before: -12.8 => after: -13
.toFixed() before: 12.1 => after: 12 .toFixed() before: -12.9 => after: -13
.toFixed() before: 12 => after: 12 .toFixed() before: -13 => after: -13

Code

Here is the code that I used to create the List of rounding numbers.

type ChangeFunction = (n: number) => number;
const calcNum = (tag: string, num: number, func: ChangeFunction) => {
    const afterNum = func(num);
    console.log(`${tag}  before: ${num} => after: ${afterNum}`);

    // I noticed that, when debugging, we shouldn't format the number or string.
    // const beforeVal = new Intl.NumberFormat('ja-JP', { style: 'decimal', 'minimumFractionDigits': 1} ).format(num);
    // const afterVal = new Intl.NumberFormat('ja-JP', { style: 'decimal', 'minimumFractionDigits': 1} ).format(afterNum);
    // console.log(`${tag}  before: ${beforeVal} => after: ${afterVal}`);
}

for (let i=0; i < 11;i++) {
    calcNum('Math.round()', 13 - i * 0.1, (n: number) => {return Math.round(n)})
}
for (let i=0; i < 11;i++) {
    calcNum('Math.round()', -12 - i * 0.1, (n: number) => {return Math.round(n)})
}

for (let i=0; i < 11;i++) {
    calcNum('.toFixed()', 13 - i * 0.1, (n: number) => {return parseFloat((n).toFixed(0))})
}
for (let i=0; i < 11;i++) {
    calcNum('.toFixed()', -12 - i * 0.1, (n: number) => {return parseFloat((n).toFixed(0))})
}

Bug Fix

I found this.
When we calculate "6.4 - 5 * 0.01", we get "6.3500000000000005".

console.log(`calc: ${6.4 - 5 * 0.01}`);
// -> calc: 6.3500000000000005

Here is another example.

for (let i=0; i < 11;i++) {
    let val = 6.4 - i * 0.01;
    console.log(`(test) val: ${val}`);
}
// Result
(test) val: 6.4
(test) val: 6.390000000000001
(test) val: 6.380000000000001
(test) val: 6.37
(test) val: 6.36
(test) val: 6.3500000000000005
(test) val: 6.340000000000001
(test) val: 6.33
(test) val: 6.32
(test) val: 6.3100000000000005
(test) val: 6.300000000000001

So I noticed that, when debugging, we shouldn't format the number or string.
Then I changed my code to remove the formatting by "Intl.NumberFormat", so that we could detect the real number.

...
const calcNum = (tag: string, num: number, func: ChangeFunction) => {
    const afterNum = func(num);
    console.log(`${tag}  before: ${num} => after: ${afterNum}`);

    // I noticed that, when debugging, we shouldn't format the number or string.
    // const beforeVal = new Intl.NumberFormat('ja-JP', { style: 'decimal', 'minimumFractionDigits': 1} ).format(num);
    // const afterVal = new Intl.NumberFormat('ja-JP', { style: 'decimal', 'minimumFractionDigits': 1} ).format(afterNum);
    // console.log(`${tag}  before: ${beforeVal} => after: ${afterVal}`);
}
...

Discussion