Làm cách nào để tính tổng số float trong định dạng giờ và phút?


14

Làm cách nào để tính tổng số float trong định dạng giờ và phút?

Những, cái đó. nếu tính hai số như vậy 0.35+3.45thì nên = 4.20, không3.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);
});

Kết quả sẽ như thế này:

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

1
Làm thế nào bạn sẽ xác định logic?
Juhil Somaiya

6
Vì vậy, 0,2 đại diện cho 20 phút, hay 0,2 của một giờ? 1.0 có nghĩa là một giờ, hay 0,6 có nghĩa là một giờ?
Spangle

2
Xin lỗi, vậy 1.0 có nghĩa là 1 giờ và 0 phút?. Chẳng hạn 0,6 và 0,7 nghĩa là gì?
Spangle

2
Bạn sẽ tìm thấy câu trả lời ở đây: codereview.stackexchange.com/a/109478 . Chuyển đổi số của bạn thành chuỗi và trong hàm sử dụng "."để phân chia các chuỗi đó, không ":".
Gerardo Furtado

6
Bạn phức tạp với logic như vậy. 0.5Giờ nên là 30 phút, bất cứ điều gì khác là hoàn toàn phi lý. Tôi hy vọng nó không dành cho khách hàng trong cuộc sống thực .. Hoặc hoạt động với các giá trị nổi của đơn vị thời gian cố định hoặc bạn tách riêng giờ / phút. Đơn giản vậy thôi.
Kaddath

Câu trả lời:


7

Cách tốt nhất để xử lý các định dạng dữ liệu "điên" như vậy là trước tiên chuyển đổi chúng thành định dạng lành mạnh và dễ xử lý, làm bất cứ điều gì bạn cần làm bằng cách sử dụng dữ liệu đã chuyển đổi và cuối cùng (nếu bạn hoàn toàn phải) chuyển đổi kết quả trở lại định dạng ban đầu.

(Tất nhiên, giải pháp thực sự là ngừng hoàn toàn sử dụng các biểu diễn thời gian điên rồ như vậy. Nhưng điều đó không phải lúc nào cũng thực tế, ví dụ như vì bạn cần giao tiếp với một hệ thống cũ mà bạn không thể thay đổi.)

Trong trường hợp của bạn, một định dạng lành mạnh phù hợp cho dữ liệu của bạn sẽ là một số phút không thể thiếu. Khi bạn đã chuyển đổi dữ liệu của mình sang định dạng này, bạn có thể thực hiện số học thông thường trên đó.

// 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) )

Lưu ý rằng mã chuyển đổi ở trên trước tiên nhân số float đầu vào lên 100 và làm tròn nó thành một số nguyên trước khi tách các phần giờ và phút. Điều này sẽ xử lý mạnh mẽ các đầu vào với các lỗi làm tròn có thể xảy ra trong khi tránh sự cần thiết phải xâu chuỗi các đầu vào.

Lý do cần quan tâm thêm ở đây là vì số 0,01 = 1/100 (và hầu hết các bội số của nó) không thực sự chính xác trong định dạng dấu phẩy động nhị phân được sử dụng bởi JavaScript. Do đó, bạn thực sự không thể có một số JS chính xác bằng 0,01 - thứ tốt nhất bạn có thể có là một số gần đến mức chuyển đổi nó thành một chuỗi sẽ tự động che giấu lỗi. Nhưng lỗi làm tròn vẫn còn đó và có thể cắn bạn nếu bạn cố gắng làm những việc như so sánh những con số đó với một ngưỡng chính xác. Đây là một minh chứng hay và đơn giản:

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


7

// We got this after simple addition
// Now we want to change it into 4.2
sample = 3.8

// Now here are the minutes that the float currently shows
minutes = (sample % 1) * 100

// And the hours
hours = Math.floor(sample)

// Here are the number of hours that can be reduced from minutes
AddHours = Math.floor(minutes / 60)

// Adding them to the hours count
hours += AddHours

// Reducing mintues
minutes %= 60

// Finally formatting hour and minutes into your format
final = hours + (minutes / 100.0)
console.log(final)

Bạn có thể sử dụng logic này sau khi thực hiện phép cộng số học đơn giản, điều này sẽ chuyển đổi tổng thành định dạng thời gian


2
Tại sao math.floor(sample/1)thay vì chỉ math.floor(sample)?
selbie

2
@selbie, đơn giản là vì lần đầu tiên tôi chỉ thêm vào sample / 1, tôi mặc dù JS sẽ tự điều chỉnh nó bởi vì không có số thập phân nào trong số chia (như trong sample / 1.0một thời gian dài kể từ khi sử dụng JS;), nhưng tôi đã không nhanh chóng thêm vào và thêm vào floor, quên loại bỏ điều đó. Dù sao cũng cảm ơn bạn đã chỉ ra rằng
Letsintegreat

2
Bạn nên đề cập rằng điều này cần phải được thực hiện cho mọi yếu tố arrkhông nằm trong kết quả. Ví dụ: nếu arr = [1.5, 2.5]kết quả sẽ 4thay vì4.4
Tít

1
@Titus, Có, tôi đã bỏ lỡ phần đó, vì vậy chúng tôi cần tìm nạp giờ và phút từ mỗi phần tử, sau đó thêm chúng một cách riêng biệt, sau đó chỉ có cách tiếp cận của tôi sẽ hữu ích.
Letsintegreat

4

Ở đây bạn đi, thực hiện trong Javascript ES6. Tôi đã lặp từng phần tử và phân tách giờ, phút ., kiểm tra nếu phút không tồn tại khác gán 0 đếm tổng số giờ và phút và áp dụng tính toán cần thiết.

const resultObj = [0.35, 3.45].reduce((a, e) => {
  const [hours, minutes] = e.toString().split('.');
  a.h += +hours;
  a.m += (+(minutes.padEnd(2, 0)) || 0); 
  return a;
}, {h: 0, m: 0});


const result = resultObj.h + Math.floor(resultObj.m / 60) + ((resultObj.m % 60) / 100);
console.log(result);


1
Sẽ không hoạt động như hiện tại, ví dụ 0,3 sẽ chỉ được tính là ba phút chứ không phải 30 phút với giải pháp của bạn.
Spangle

3

Bạn cần chuyển đổi mọi thứ hoặc thành giờ hoặc thành phút và sau đó làm toán.

Example: 0.35 + 3.45
Convert 0.35 to Hours Number((35/60).toFixed(2))
= 0.58

Then convert 3hours 45 minutes into hours
= 3 + Number((45/60).toFixed(2))
= 3hours + 0.75 hours
= 3.75

Add the 2 conversions
= 0.58 + 3.75
= 4.33 hours

Convert the 0.33 back to minutes by multiplying by 60
= 4 hours 19.8 minutes ~ 20 mins

Hope that helps!

2

Bạn phải chuyển đổi chúng thành giờ và phút đầu tiên

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];

function add(arr) {
  var hm = arr
    .map(v => [Math.floor(v), (v % 1).toFixed(2) * 100])  // Map the array to values having [hours, minutes]
    .reduce((t, v) => { //  reduce the array of [h, m] to a single object having total hours and minutes
      t = {
        h: t.h + v[0],
        m: t.m + v[1]
      };
      return t;
    }, {
      h: 0,
      m: 0
    });

  // final result would be = 
  // total hours from above
  // + hours from total minutes (retrived using Math.floor(hm.m / 60)) 
  // + minutes (after converting it to be a decimal part)
  return (parseFloat(hm.h + Math.floor(hm.m / 60)) + parseFloat(((hm.m % 60) / 100).toFixed(2))).toFixed(2);
}

// adding `arr` array
console.log(add(arr));

// adding 0.35+3.45
console.log(add([0.35, 3.45]));


2
Thật không may, không ai nhận thấy điều này lúc đầu. Và mặc dù có lẽ đúng, học tập ở đâu? Sao chép và dán từ OP của giải pháp của bạn sẽ giúp ích rất nhiều trong thời gian ngắn. Nhưng đó là một câu hỏi thông minh xứng đáng được giải thích thông minh.
Get set

2

Tôi có thể biết tại sao bạn muốn kết quả đầu tiên là 0 không? Dưới đây là một cách để làm điều này với một vòng lặp duy nhất. Bình luận là trong mã để giải thích. Với mỗi vòng lặp, chúng tôi thêm số phút và nếu chúng lớn hơn 60, chúng tôi thêm một giờ và sau đó sử dụng % 60 để nhận các phút còn lại. Phao có thể là một nỗi đau để làm việc với,

ví dụ: 1.1 + 2.2 === 3.3 là sai

Vì vậy, tôi đã chuyển đổi các số thành một chuỗi, và sau đó trở lại một int.

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];
let hoursTally = 0;
let minutesTally = 0;

for(var i = 0; i < arr.length; i++) {
  // Convert the float to a string, as floats can be a pain to add together
  let time = arr[i].toString().split('.');
  // Tally up the hours.
  hoursTally += parseInt(time[0]);
  // Tally up the minutes;
  let minute = time[1];
  if(minute) {
    // We do this so we add 20 minutes, not 2 minutes
    if(minute.length < 2) {
      minutesTally += parseInt(minute) * 10;
    } else {
      minutesTally += parseInt(minute);
    }
    // If the minutesTally is greater than 60, add an hour to hours
    if(minutesTally >= 60) {
      hoursTally++;
      // Set the minutesTally to be the remainder after dividing by 60
      minutesTally = minutesTally % 60;
    }
  }
  console.log(hoursTally + "." + minutesTally);
}


uh .. bằng mọi cách .. 2.2 + 1.1 IS 3.3 với ý nghĩa là 3h30 phút
đại bàng275

1
toString().split('.');- argh, thật sao?
dùng253751

3
@ Eagle275 Nhưng số 1.1 + 2.2 không phải là 3.3 khi các số là dấu phẩy động. Đó là 3.3000000000000001 hoặc 3.29999999999999 hoặc một cái gì đó. Đó là bởi vì 1.1 không thực sự là 1.1 và 2.2 không thực sự là 2.2 và 3.3 không thực sự là 3.3 ở điểm nổi.
dùng253751

đừng bắt đầu chia tóc - Tôi sẽ không chọn sơ đồ số kỳ lạ này ngay từ đầu ... khi tôi bắt đầu lập trình, tôi có thể đã chuyển đổi mọi thứ thành vài phút (hoặc giây nếu cần thiết) - chuyển đổi chúng trở lại để hiển thị .. nhưng ngày nay các quy tắc DateTime trong mắt tôi
Eagle275

1

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]

const reducer = (acc, curr) => {
  acc = `${acc}`.split('.').length > 1 ? acc : `${acc}.0`;
  curr = `${curr}`.split('.').length > 1 ? curr : `${curr}.0`;
  let hours = parseStrAndSum(true, `${acc}`.split('.')[0], `${curr}`.split('.')[0]);
  let minute = parseStrAndSum(false, `${acc}`.split('.')[1], `${curr}`.split('.')[1]);
  hours = parseInt(hours / 1) + parseInt(minute / 60);
  minute = minute % 60;
  console.log(`${acc} + ${curr} = ${hours}.${minute}`);
  return `${hours}.${minute}`;
}

const parseStrAndSum = (is_hours, ...strs) => {
  let result = 0;
  strs.forEach(function(number) {
    if (!is_hours) {
      number = number.length == 1 ? `${number}0` : number;
    }
    result += parseInt(number);
  });
  return result;
};

arr.reduce(reducer);


1
@lan 0.15 + 0.2 Vì sao =0.17? Phải là0.35
12916796

1
Lúc đó tôi nghĩ rằng số thập phân 0,2 bằng hai phút thay vì 20 phút. Bây giờ tôi đã điều chỉnh mã, xin vui lòng xác nhận lại.
Ian

1

Cách tiêu chuẩn để giảm mô-đun là thêm thâm hụt sau khi thêm nếu xảy ra tràn. Đây là cách bạn thực hiện bổ sung BCD bằng phần cứng nhị phân chẳng hạn.

Mặc dù bạn có thể thực hiện bổ sung bằng cách sử dụng phao theo cách này, có một câu hỏi là liệu bạn có nên . Các vấn đề với việc sử dụng số float để vận hành với số lượng cơ bản là số nguyên đã được biết đến và tôi sẽ không thử lại chúng ở đây.

Thông thường, phần bổ sung trên phân số float hoạt động hoàn toàn với mô đun 1.0, phần tràn ra khỏi phân số làm tăng phần nguyên. Nếu chúng ta giải thích điểm là dấu phân cách hours.minutes, thì chúng ta muốn phân số tràn vào 0,6. Điều này cần thâm hụt 0,4 để được thêm vào thời điểm thích hợp.

function add_float_hours_minutes(a, b)
{
  var trial_sum = a+b;
  // did an actual overflow occur, has the integer part incremented?
  if ( Math.floor(trial_sum) > Math.floor(a)+Math.floor(b) )  {
    trial_sum += 0.4;
  }
  // has the fractional part exceeded its allotted 60 minutes?
  if ( trial_sum-Math.floor(trial_sum) >= 0.6)  {
    trial_sum += 0.4;
  }
  return trial_sum;
}

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);
  sum = add_float_hours_minutes(sum, parseFloat(item));
});

tạo ra đầu ra sau, chính xác trong vòng làm tròn với những gì OP yêu cầu

0
0.15
0.35
4.2
5.000000000000001
7.000000000000001
7.300000000000001
12.5
13.5
15.3
16.400000000000002
19.2
20.2

Tôi đã để lại định dạng cuối cùng đến hai chữ số thập phân như một bài tập cho người đọc. 15 chữ số kéo dài trong tất cả vinh quang của họ minh họa một phần lý do tại sao sử dụng phao không phải là cách tốt nhất để làm điều này.

Ngoài ra, hãy xem xét những gì xảy ra khi bạn muốn bao gồm giây hoặc ngày. Hai cách khá chuẩn hơn là giây trôi nổi, hoặc một bộ số nguyên, đột nhiên trông hợp lý hơn rất nhiều.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.