【问题标题】:django float or decimal are rounded unintentionally when savingdjango 浮点数或小数在保存时被无意舍入
【发布时间】:2016-11-27 02:02:30
【问题描述】:

我想在 Place 模型中保存纬度和经度。 我尝试了两个字段,floatfield 和 decimalfield。

1。 FloatField 模型

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

2。 DecimalField 模型

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

两个字段都适用于以下值。

10.1
10.12
10.123
10.1234
...
10.1234567890123

但是,在第 16 位数字(不是“十六位小数”)之后,在保存时会无意四舍五入。

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

我在 django 文档中找不到有关此“无意回合”的任何解释。请帮忙。谢谢。

【问题讨论】:

  • 哪个数据库、操作系统和架构?
  • 我的服务器是ubuntu 64bit mysql。我的本地是 ubuntu 64bit。 mysql和localhost sqlite都会出现这个问题。

标签: python django floating-point decimal latitude-longitude


【解决方案1】:

您在 django 文档中找不到“无意舍入”,因为 django 不是这里的罪魁祸首。

当您的列数据类型为浮点数时,它是 MYSQL 进行舍入的。

为了获得最大的可移植性,需要存储近似数值数据值的代码应使用 FLOATDOUBLE PRECISION,不指定精度或位数。

由于浮点值是近似值而不是存储为精确值,因此在比较中尝试将它们视为精确值可能会导致问题。它们还受制于平台或实现依赖项。

但为了值的准确性,您应该使用 DecimalField

您说您使用了 DecimalField 并且数字仍在四舍五入。这可能是因为您的 表格列 仍然是 Float 类型,而不是 Decimal

将表格列类型更改为十进制,您可以看到更改。

示例 SQL 语法 ALTER TABLE your_table MODIFY latitude decimal(m,n);, OR

如果您使用的是 MYSQL Workbench 或任何 UI 界面,请直接从列信息选项卡中更改它(他们有一个)

DECIMAL 和 NUMERIC 类型存储精确的数字数据值。当保持精确精度很重要时使用这些类型

在 DECIMAL 列声明中,可以(并且通常是)指定精度和小数位数;例如:纬度 DECIMAL(m,n)

精度(m)表示为值存储的有效位数,比例(n)表示可以存储的位数小数点。

在此处为您的字段纬度和经度提供所需的精度比例

请参阅here 了解有关 Decimal 数据类型的更多信息,请参阅here 了解有关您遇到的问题的信息。

【讨论】:

  • 非常感谢。这是因为 django 默认数据库“sqlite3”不支持具有那么多小数位的十进制字段。我已将本地数据库更改为 mysql 并解决了问题。谢谢。
  • 我很高兴它帮助了@jeyongOh :-)
猜你喜欢
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2012-11-08
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
相关资源
最近更新 更多