Math.trunc() 没有正确舍入值

Math.trunc() not rounding values properly

我知道在 JavaScript 中肯定有更好的方法来做到这一点,但我只是在做一些我知道的事情。我正在做另一个 Code Wars 挑战,当我应该得到 12:34:56.

时似乎得到了 12:34:55

对于挑战,函数以几秒钟的格式给出输入,例如。 86399,然后输出应该是人类可读的格式。

我真的不知道这里出了什么问题,感觉它与 Math.trunc() 有关,因为我的数学是有道理的。

我会解释数学,但它在代码中很容易解释。唯一的问题似乎是秒数。

function humanReadable(seconds) {
    const hour = Math.trunc((seconds / 60) / 60);
    const mins = Math.trunc((((seconds / 60) / 60) - hour) * 60); 
    const secs = Math.trunc(((seconds / 60) - Math.trunc(seconds / 60)) * 60);

    return `${hour < 10 ? `0${hour}` : hour}:${mins < 10 ? `0${mins}` : mins}:${secs < 10 ? `0${secs}` : secs}`
}

您应该尝试使用模数来计算每次除法后的余数,如下面的代码片段所示。

let d = 86399;
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.trunc(d % 60);
var result = `${h < 10 ? `0${h}` : h}:${m < 10 ? `0${m}` : m}:${s < 10 ? `0${s}` : s}`
console.log(result);

问题是由于浮点数不能准确表示数字

在 45296 的情况下 - 即 12:34:56

A: seconds / 60                    = 754.9333333333333
B: Math.trunc(seconds / 60)        = 754
A - B (should be 0.9333333333333)  =   0.9333333333332803

你可以看到,它比它应该的少,但即使是 0.9333333333333 * 60 也是 55.999999999998 ...截断它,你得到 55

一种解决方法是

const secs = Math.round(((seconds / 60) - Math.trunc(seconds / 60)) * 60);

而且,也许还有

const mins = Math.trunc((((seconds / 60) / 60) - hour) * 60); 

会议记录“失败”的案例超过 600 起

Actually, don't do that, it doesn't fix the 600 or so where the minutes are wrong!

更简单的方法是使用 modulo % 运算符

此代码中除法的结果将始终仅为“整数”,因为一旦您去掉 mod 60,除数将始终是 60 的精确倍数(因为这只是之后的余数除以 60) - 数学! :p

function humanReadable(seconds) {
    const ss = seconds % 60;
    seconds = (seconds - ss) / 60;
    const mm = seconds % 60;
    const hh = (seconds - mm) / 60;
    return [hh,mm,ss].map(v => (''+v).padStart(2, 0)).join(':');
}


console.log(humanReadable(45296))

或者,您可以只使用日期 object 并让它为您完成所有工作

function humanReadable(seconds) {
    const d = new Date(0);
    d.setUTCSeconds(seconds);
    const hh = d.getUTCHours().toString().padStart(2, '0');
    const mm = d.getUTCMinutes().toString().padStart(2, '0');
    const ss = d.getUTCSeconds().toString().padStart(2, '0');
    return `${hh}:${mm}:${ss}`;
}

console.log(humanReadable(45296))

我还包括了另一种获取前导零的方法 - 这只是我的习惯,这些说使用 padStart 等

在 padStart 出现之前,而不是

hour < 10 ? `0${hour}` : hour

我愿意

`0${hour}`.substr(-2)

但是因为你使用的是模板文字,所以你肯定有 padStart :p