How to sum float numbers in the format hours and minutes?

user12916796 :

How to sum float numbers in the format hours and minutes?

Those. if calculate two such numbers 0.35+3.45 then it should be = 4.20, not 3.80

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]
    
var sum = 0.0;
    
arr.forEach(function(item) {
  console.log(sum);
  sum += parseFloat(item);
});

The result should be like this:

0
0.15
0.35
4.20
5.0
7.0
7.30
12.50
13.50
15.30
16.40
19.20
20.20
Ilmari Karonen :

The best way to deal with "crazy" data formats like that is to first convert them into a sane and easily processable format, do whatever you need to do using the converted data and finally (if you absolutely have to) convert the results back to the original format.

(Of course, the real solution is to stop using such crazy time representations entirely. But that's not always practical, e.g. because you need to interface with a legacy system that you cannot change.)

In your case, a suitable sane format for your data would be e.g. an integral number of minutes. Once you've converted your data to this format, you can then do ordinary arithmetic on it.

// converts a pseudo-float of the form hh.mm into an integer number of minutes
// robust against floating-point roundoff errors, also works for negative numbers
function hhMmToMinutes(x) {
  const hhmm = Math.round(100 * x)  // convert hh.mm -> hhmm
  return 60 * Math.trunc(hhmm / 100) + (hhmm % 100)
}

// convert minutes back to hh.mm pseudo-float format
// use minutesToHhMm(minutes).toFixed(2) if you want trailing zeros
function minutesToHhMm(minutes) {
  return Math.trunc(minutes / 60) + (minutes % 60) / 100
}

const arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]

let sum = 0
console.log( arr.map(hhMmToMinutes).map(x => sum += x).map(minutesToHhMm) )

Note that the conversion code above first multiplies the input float by 100 and rounds it to an integer before separating the hour and minute parts. This should robustly handle inputs with possible rounding errors while avoiding the need to stringify the inputs.

The reason for taking extra care here is because the number 0.01 = 1/100 (and most of its multiples) is not actually exactly representable in the binary floating-point format used by JavaScript. Thus you can't actually have a JS number that would be exactly equal 0.01 — the best you can have is a number that's so close that converting it to a string will automatically hide the error. But the rounding error is still there, and can bite you if you try to do things like comparing such numbers to a exact threshold. Here's a nice and simple demonstration:

console.log(Math.trunc(100 * 0.29))  // you'd think this would be 29...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=6891&siteId=1