Rails 在 DB 级别舍入浮点数

发布于 2024-12-20 22:58:08 字数 497 浏览 0 评论 0原文

我有一个带有浮动列的表(我正在使用MySQL,mysql2 gem,一切都是标准的)

create_table :some_table do |t| 
  t.float  :amount 
end 

我在控制台中玩,当我做

a = SomeTable.new
a.amount = 9999.99
a.save!
#9999.99
a.amount
#9999.99
a.reload
a.amount
#9999.99

一切正常时

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
a.amount 
#9999.999
a.reload
a.amount
#10000.00

,你会看到 ruby​​ (或rails)对数字进行四舍五入。

有人能解释一下这是为什么吗? ……还是只有我一个人?

I have table with float column (I'm using MySQL, mysql2 gem, everything standard)

create_table :some_table do |t| 
  t.float  :amount 
end 

I was playing around in console, when i do

a = SomeTable.new
a.amount = 9999.99
a.save!
#9999.99
a.amount
#9999.99
a.reload
a.amount
#9999.99

everything ok

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
a.amount 
#9999.999
a.reload
a.amount
#10000.00

as you see ruby (or rails ) rounds the numbers.

Can someone explain me why is that? ...or is just me ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

∞梦里开花 2024-12-27 22:58:09

如果您想了解有关浮点数的所有信息以及它们为何具有舍入误差,请参阅 每个计算机科学家都应该了解浮点运算

如果您想做货币计算,请不要使用浮动!使用定点数据类型。
如果您使用 Rails 迁移,则小数类型就是您想要的 此处描述

If you want to know all about floats and why they have rounding errors, see What Every Computer Scientist Should Know About Floating-Point Arithmetic.

If you are tying to do currency calculations, don't use float! Use a fixed point data type.
If you use rails migrations, the decimal type is what you want as described here.

你不是我要的菜∠ 2024-12-27 22:58:09

接受的答案通常是正确的(并且使用十进制而不是浮点数可以解决该问题)。

然而,这里还有一个更深层次的问题。

mysql2 驱动程序未指定它希望 mysql 返回的精度,因此数据库返回截断的结果。

您可以通过将金额乘以浮点数来强制 mysql 返回完整精度。

class SomeTable
  default_scope -> { select("some_tables.*, amount * 1.0000000000000000 as amount")}
end

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
SomeTable.last.amount 
#9999.999
SomeTable.unscoped.last.amount
#10000.00

Accepted answer is correct in general (and using decimal instead of float will work around the problem).

However, there's a deeper issue here.

The mysql2 driver isn't specifying the precision it wants mysql to return, so the database is returning truncated results.

You can force mysql to return the full precision by multiplying the amount by a float.

class SomeTable
  default_scope -> { select("some_tables.*, amount * 1.0000000000000000 as amount")}
end

a = SomeTable.new
a.amount = 9999.999
a.save!
#9999.999
SomeTable.last.amount 
#9999.999
SomeTable.unscoped.last.amount
#10000.00
恋你朝朝暮暮 2024-12-27 22:58:09

MySQL 文档将 float 描述为“近似数字数据类型”...可能不适合存储货币值。尝试将“金额”定义为小数

The MySQL documentation describes float as an "approximate numeric data type"...probably not good for storing money values. Try defining "amount" as a decimal, instead.

别挽留 2024-12-27 22:58:09

看起来数据库是在进行数字更改的。

我相信这里发生的情况是,正在创建的 MSSQL 表的精度仅为小数点以下两位数(或者很难以小数形式存储精度),因此在此之后放入的任何内容都会被数据库四舍五入,但是不是代码。

It looks like the database is the one doing the number changing.

I believe what's happening here is that the MSSQL table being created has a precision of only two digits below the decimal point (or has a hard time storing precision in decimal form), so anything put in after that is getting rounded by the database, but not the code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文