2012-07-23 34 views
8

Ứng dụng web được mã hóa bằng PHP với cơ sở dữ liệu MySQL.Số tiền chính xác với số tiền chia, đối chiếu lỗi làm tròn

Tôi có một hệ thống tính toán chi phí khác nhau cho một số người khi chia chi phí. Ví dụ: Người A mua thứ gì đó cho 10 và Người B, C và D nên chia chi phí.

Hệ thống này nên do đăng ký kỷ lục dương tính với người Một 10 và hồ sơ tiêu cực của 10/3 cho B, C và D.

Tuy nhiên, khi điều này được thực hiện; B, C và D tất cả đều có -3.33 sau khi làm tròn. Trong đó tất nhiên không thêm vào tổng số 10. Cách tốt nhất để giải quyết vấn đề này là gì? Một giải pháp tối ưu sẽ ngẫu nhiên những gì người nhận được là chi phí hơi lớn hơn là tốt.

Một giải pháp khả thi là nếu tôi chỉ để khoản nợ của người cuối cùng là 10 - (A + B), nhưng sau đó có vấn đề nếu bốn người chia một chi phí ví dụ 13.34. Các phần khác nhau sau đó sẽ là 3,34, 3,34, 3,34 và 3,32, trong khi phân chia tối ưu sẽ là 3,34, 3,34, 3,33, 3,33.

Một số có thể cho rằng với số thập phân đủ đây chỉ là vấn đề khi có số lượng lớn hàng. Nhưng trong một hệ thống kinh tế, tôi nghĩ rằng điều quan trọng là phải có một hệ thống không an toàn ngay cả khi bắt đầu. Nó cần phải là có thể mở rộng và thậm chí không thể có lỗi nhỏ nhất. Tính không lành mạnh là không sao, không phải lỗi.

vấn đề tương tự: sum divided values problem (dealing with rounding error)

+0

"Sự không lành mạnh là ổn, không phải lỗi." - yêu thích nó – user1020317

+0

+1 bản trình bày – Smandoli

+0

Tôi nghĩ rằng tôi sẽ tìm thấy hai giá trị chia gần nhất, sau đó chuyển đổi giữa hai khi chúng được gán. Sau đó, tìm hiểu xem phải làm gì với giá trị kỳ quặc cuối cùng (tiềm năng). – Smandoli

Trả lời

1

Điều này dường như hoạt động - http://jsfiddle.net/nQakD/.

Được sử dụng jQuery làm ví dụ, nhưng nếu bạn biết PHP, bạn sẽ có thể dễ dàng chuyển đổi nó sang PHP. Nếu bạn cần mã php, hãy cho tôi biết, tôi sẽ viết nó cho bạn.

tôi sẽ dán mã ở đây cũng -

$(document).ready(function() { 
    var price = 17.48, people = 4, payment = (price/people).toFixed(2), count=0; 
    var payments = []; 
    for(i = 0; i < people; i++) { 
     payments.push(payment); 
    } 

    if(payment*people != price) { 
     var currentPayment = payment*people; 

     $(payments).each(function() { 
      if(currentPayment < price) { 
       currentPayment = (currentPayment-this).toFixed(2); 
       var newPayment = parseFloat(this)+0.01; 
       payments[count] = newPayment.toFixed(2); 
       currentPayment = parseFloat(currentPayment)+parseFloat(newPayment); 
      } 
      else if(currentPayment > price) { 
       currentPayment = (currentPayment-this).toFixed(2); 
       var newPayment = parseFloat(this)-0.01; 
       payments[count] = newPayment.toFixed(2); 
       currentPayment = parseFloat(currentPayment)+parseFloat(newPayment); 
      } 
      count++; 
     }); 

    } 
    $(payments).each(function() { 
     $("#result").append("<b>"+this+"</b><br/>"); 
    });  
});​ 

EDIT:

Và đây đang làm việc mã php -

$price = 13.34; 
$people = 4; 
$payment = (float)$price/$people; 
$payment = 0.01 * (int)($payment*100); 
$count = 0; 
$payments = Array(); 
for($i = 0; $i < $people; $i++) { 
    array_push($payments, $payment); 
} 
if($payment*$people != $price) { 
    $currentPayment = $payment*$people; 
    foreach($payments as $pay) { 
     if($currentPayment < $price) { 
      $currentPayment = $currentPayment-$pay; 
      $currentPayment = 0.01 * (int)($currentPayment*100);    
      $newPayment = (float)$pay+0.01; 
      $newPayment = 0.01 * (int)($newPayment*100); 
      $payments[$count] = $newPayment; 
      $currentPayment = (float)$currentPayment+$newPayment; 
     } 
     else if($currentPayment > $price) { 
      $currentPayment = $currentPayment-$pay; 
      $currentPayment = 0.01 * (int)($currentPayment*100);    
      $newPayment = (float)$pay-0.01; 
      $newPayment = 0.01 * (int)($newPayment*100); 
      $payments[$count] = $newPayment; 
      $currentPayment = (float)$currentPayment+$newPayment; 
     } 
     $count++; 
    } 
} 
foreach($payments as $payed) { 
    echo '<b>'.$payed.'</b><br />'; 
}​​​ 

EDIT 2:

Cái này sh có thể khắc phục vấn đề js - http://jsfiddle.net/nQakD/ cũng đã cập nhật mã ở trên.

EDIT 3:

Edited mã PHP và mã JS nên nó không làm việc cho tất cả các ví dụ - http://jsfiddle.net/nQakD/.

+0

Cảm ơn bạn rất nhiều! Tuy nhiên, một số câu hỏi: ** 1. ** khi truyền $ thanh toán làm int, có phải kết quả là 3,33 hoặc 3,34, tức là. tròn hay không? ** 2. ** Khi thử các giá trị khác nhau trong tập lệnh js tuyệt vời của mình, tôi có thể nhận được các giá trị không được làm tròn thành hai số thập phân. Tôi có nên làm một int-cast tương tự ở đâu đó trong if-tuyên bố? –

+0

1) Nó sẽ dẫn đến 3.33. 2) Bạn có thể cho tôi một số ví dụ không? – y2ok

+0

Kiểm tra câu trả lời mới. – y2ok

0

Có thể làm cho một "cân bằng làm tròn" mới lên cho mỗi người dùng. Nếu đó là 10 được chia ba cách, thì mỗi người dùng sẽ trả 3,34. Mỗi người dùng cũng sẽ có 2/3 xu cho số dư làm tròn của họ. (điều này sẽ phải được lưu trữ dưới dạng văn bản tôi đoán). Tiếp theo thời gian cùng một điều xảy ra, kiểm tra số dư làm tròn .. Họ có 2/3 của một cent, vì vậy bây giờ bạn có thể mất một phần ba off (vì vậy bây giờ họ có 1/3 của một trong số dư làm tròn) và chỉ tính phí 3.33.

Các vấn đề liên quan