Alexander Veheecke
Alexander Veheecke

Reputation: 47

JavaScript float not truncating correctly

I am struggling to get the float number to show correctly. It works for the most part. For example, if I input 0.2 in "kWh" and 0.04 in "Hours used", it outputs 0.008 in "Total. However, when I change these values to 0.02 and 0.23, it outputs 0.046000000000000006. Why doesn't it output 0.046 instead? What am I missing here?

<script>
        function calculate(){
            var amount = document.getElementById("kW").value;
            var amount = parseFloat(amount).toFixed(2);
            var quantity = document.getElementById("hours").value;
            var quantity = parseFloat(quantity).toFixed(2);
            var total = amount * quantity;
            document.getElementById("total").value = total;
        }
    </script>
<div class="kWattsCol">
                <p><b>kWh</b></p>
                <input type="number" oninput="calculate()" id="kW" required>
            </div>

            <div class="hoursCol">
                <p><b>Hours used</b></p>
                <input type="number" oninput="calculate()" id="hours"required>
            </div>

            <div class="totalCol">
                <p><b>Total</b></p>
                <input type="text" id="total" readonly>
            </div>

Upvotes: 0

Views: 45

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 222754

Correction

… when I change these values to 0.02 and 0.23, it outputs 0.046000000000000006…

The floating-point product of these would be a number near .0046, not near .046. So I suspect the actual input was “0.2” and “0.23”. The answer below proceeds on this basis.

Discussion

When default JavaScript formatting of numbers is used, it produces just enough significant digits to uniquely distinguish the floating-point number from its neighbors in the floating-point format. This answer describes this further.

When the input “0.2” is converted to the floating-point format JavaScript uses (IEEE-754 binary64, also called “double precision”), the result is 0.200000000000000011102230246251565404236316680908203125. When “0.04” is converted, the result is 0.040000000000000000832667268468867405317723751068115234375. When these are multiplied, the result is 0.008000000000000000166533453693773481063544750213623046875. (This includes rounding of the real-number-arithmetic product to the nearest value representable in the floating-point format.)

Here is the neighbor before the result, the result, and the neighbor after the result:

0.00799999999999999843180997771696638665162026882171630859375
0.008000000000000000166533453693773481063544750213623046875
0.00800000000000000190125692967058057547546923160552978515625

Observe that .008 is closest to the middle of these, the arithmetic result. That means, when 0.008000000000000000166533453693773481063544750213623046875 is formatted for display, we only need to produce “0.008” to identify it.

In the second case, converting “0.23” yields 0.2300000000000000099920072216264088638126850128173828125, and then the product is 0.046000000000000006161737786669618799351155757904052734375.

Looking at the neighbor before, the result, and the neighbor after, we have:

0.04599999999999999922284388276239042170345783233642578125
0.046000000000000006161737786669618799351155757904052734375
0.0460000000000000131006316905768471769988536834716796875

Observe that .046 is closer to the neighbor before rather than to the result; it differs by less than one in the nineteenth decimal place, whereas the result differs by more than 6. Therefore, to identify the result, we need to produce “0.046000000000000006”.

Upvotes: 1

Related Questions