Search code examples
javascriptfloating-pointprecision

What is the best approach to deal with floating point issues when limiting the user input to 2 decimal places?


I am currently creating an application that allows users to input a weight and select their preferred unit, between kg and lbs. As of now, the database is written in Django and stores each user weight entry for a particular date as a string with 2 decimal points precision, such as,

weight_kg = models.DecimalField(max_digits=5, decimal_places=2, validators=[MinValueValidator(1)])

The problem I am facing is loss of data when changing between units. For example if a user chooses 165 with lbs as the unit, I will store this in my database as 74.84. When closing and reopening the page, it will fetch the data and attempt to restore it. Doing it, it will change 74.84kg to 164.99lbs. A loss of data, as we have no idea if the user chose 164.99lbs or it was a rounding error.

I was starting to think that I made a mistake choosing to store the weights as precisely as the user inputted them (Precisely 2dp of precision in my Django field). Using numbers, the same problem will occur too,

let kg_to_lbs = 2.20462;
let lbs_to_kg = 0.453592;
((165 * lbs_to_kg) * kg_to_lbs) // 164.99....

Is their any best practices to prevent such issues?

Additional information,

  1. User input is restricted to 2 decimal points, 0 to 1000 using a spinbutton.
  2. The database stores the weights in kg, the client is responsible for converting them back to the unit used for display and converting them to kg before sending them to the server for storage.

Solution

  • (a) Use the proper kilogram-to-pound factor. By international agreement and definition, a pound is .453 592 37 kilogram.

    (b) Convert pounds to kilograms properly, by dividing by the kilogram-to-pound factor, rather than by multiplying by a rounded reciprocal (particularly one rounded to only six significant digits).

    (c) Store the weight in finer units. Simply using pounds as the units instead of kilograms results, with the above, in a conversion that accurately recovers inputs up to at least 108 kilograms. However, there are multiple ways this can be done, including:

    • Store the weight as pounds with two digits after the decimal point, as mentioned above.
    • Store the weight as kilograms with more than two digits after the decimal point.
    • Store the weight as an integer number of grams (mathematically equivalent to the above).