Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django float or decimal are rounded unintentionally when saving

I want to save latitude and longitude in Place model. I tried two fields, floatfield and decimalfield.

1. FloatField model

class Place1(models.Model):
    latitude = models.FloatField()
    longitude = models.FloatField()

2. DecimalField model

class Place2(models.Model):
    latitude = models.DecimalField(max_digits=18, decimal_places=16)
    longitude = models.DecimalField(max_digits=19, decimal_places=16)

Both Fields work well on below values.

10.1
10.12
10.123
10.1234
...
10.1234567890123

However, after 16th number(not 'sixteen decimal places'), it's unintentionally rounded when saving.

place1 = Place1.objects.create(
            latitude=10.123456789012345,
            longitude=100.123456789012345
         )

>>place1.latitude
10.123456789012345 # works well

>>place1.longitude
100.123456789012345 # works well

# Unintentionally rounded when I get object from db. 
>>Place.objects.last().latitude
10.12345678901235 # unintentionally rounded

>>Place.objects.last().longitude
100.1234567890123 # unintentionally rounded



place2 = Place2.objects.create(
        latitude=Decimal('10.123456789012345'),
        longitude=Decimal('100.123456789012345')
     )

>>place2.latitude
Decimal('10.1234567890123450') # works well

>>place2.longitude
Decimal('100.1234567890123450') # works well

# Unintentionally rounded when I get object from db. 
>>Place.objects.last().latitude
Decimal('10.1234567890123500') # unintentionally rounded

>>Place.objects.last().longitude
Decimal('100.1234567890123000') # unintentionally rounded

I can't find any explanation about this 'unintentional round' in django document. Please help. Thanks.

like image 315
jeyongOh Avatar asked Jul 23 '16 06:07

jeyongOh


1 Answers

You can not find 'unintentional rounding' in django docs because django is not the culprit here.

Its the MYSQL that does the rounding when your column data type is Float.

For maximum portability, code requiring storage of approximate numeric data values should use FLOAT or DOUBLE PRECISION with no specification of precision or number of digits.

Because floating-point values are approximate and not stored as exact values, attempts to treat them as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies.

But for exactness of values you should use DecimalField.

You said you have used DecimalField and the numbers are still rounding-off. That might be happening because your table column is still type Float and not Decimal.

Change you table column type to Decimal and you can see the change.

Example SQL syntax ALTER TABLE your_table MODIFY latitude decimal(m,n);, OR

If you are using MYSQL Workbench or any UI interface, change it directly from the columns info tab (they have one)

The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision

In a DECIMAL column declaration, the precision and scale can be (and usually is) specified; for example: latitude DECIMAL(m,n)

The precision (m) represents the number of significant digits that are stored for values, and the scale (n) represents the number of digits that can be stored following the decimal point .

Help yourself here for the the precision scale you want for your fields latitude and longitude

See here for more info on Decimal data type and here for info on the issue you are encountering.

like image 138
kapilsdv Avatar answered Sep 18 '22 13:09

kapilsdv