Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

string.Format() on double values gives inaccurate results

I've got this code:

<tbody>
    @foreach (var day in user.WorkDays)
    {
        <tr>
            <th>@day.Date.ToString("MM/dd/yy")</th>
            <td>
                <ul>
                    @foreach (var note in day.Notes)
                    {
                        <li>@note.Text</li>
                    }
                </ul>
            </td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Regular * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Overtime * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Doubletime * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Sick * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Vacation * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Holiday * 100) / 100)</td>
            <td>@string.Format("{0:0.00}", Math.Truncate(day.Totals.Overall * 100) / 100)</td>
        </tr>
    }
</tbody>
<tfoot>
    <tr>
        <th>Totals:</th>
        <th></th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Regular * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Overtime * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Doubletime * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Sick * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Vacation * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Holiday * 100) / 100)</th>
        <th>@string.Format("{0:0.00}", Math.Truncate(user.Totals.Overall * 100) / 100)</th>
    </tr>
</tfoot>

It produces this result:

enter image description here

(Open the image in a new tab to see it full-sized.)

If you look at the values on the right-most column, you'll notice that they do not add up to the 79.98 at the bottom right of the table. I calculated that they add up to 79.93.

Since I know somebody is going to ask, yes, 79.98 is the correct total. It's the values that are supposed to add up to that total that are incorrect.

What am I doing wrong? I've been fiddling around with this for far too long and haven't seen any change.

Edit:

After reading some comments, it's clear that the Math.Truncate() calls are not helping. Here's what I had previously:

<tbody>
    @foreach (var day in user.WorkDays)
    {
        <tr>
            <th>@day.Date.ToString("MM/dd/yy")</th>
            <td>
                <ul>
                    @foreach (var note in day.Notes)
                    {
                        <li>@note.Text</li>
                    }
                </ul>
            </td>
            <td>@day.Totals.Regular.ToString("0.00")</td>
            <td>@day.Totals.Overtime.ToString("0.00")</td>
            <td>@day.Totals.Doubletime.ToString("0.00")</td>
            <td>@day.Totals.Sick.ToString("0.00")</td>
            <td>@day.Totals.Vacation.ToString("0.00")</td>
            <td>@day.Totals.Holiday.ToString("0.00")</td>
            <td>@day.Totals.Overall.ToString("0.00")</td>
        </tr>
    }
</tbody>
<tfoot>
    <tr>
        <th>Totals:</th>
        <th></th>
        <th>@user.Totals.Regular.ToString("0.00")</th>
        <th>@user.Totals.Overtime.ToString("0.00")</th>
        <th>@user.Totals.Doubletime.ToString("0.00")</th>
        <th>@user.Totals.Sick.ToString("0.00")</th>
        <th>@user.Totals.Vacation.ToString("0.00")</th>
        <th>@user.Totals.Holiday.ToString("0.00")</th>
        <th>@user.Totals.Overall.ToString("0.00")</th>
    </tr>
</tfoot>

Now, those values add up to 80 even. Even that's .02 higher than the actual value.

like image 446
keeehlan Avatar asked Jan 11 '23 16:01

keeehlan


1 Answers

So here's the real question - should the "total" be the total of the original numbers or the truncated numbers. (As a side note, ROUND would reduce the error but not eliminate it.). If the total should be the sum of the original numbers then you can either:

  1. Leave the report alone and explain in a footnote that the total may not match exactly due to rounding.
  2. Add a row for "rounding error".
  3. Allocate the rounding error to one or more of the items (here's a question and argument I had on how to do that)

If the total should be the total of the rounded numbers, then that's easy to do in the report, but it won't match the total of the original numbers (unless you round the original numbers in the source).

like image 102
D Stanley Avatar answered Jan 18 '23 22:01

D Stanley