如何在不出现浮点舍入误差的情况下存储重量/体积的数值并在单位(g > kg)之间进行转换?
How to store numeric values for weight / volume without getting float rounding errors and convert between units (g > kg)?
我需要在名为 PackageType 的 Rails 模型中存储一个体积和一个重量。我有两个(相关的)问题:
- 这些值可能不是整数。例如,它可能是 0.5 公斤。但我想避免与浮动相关的舍入错误:在加/乘/除后,我不想冒险得到 1.00000001kg(主要是出于会计原因)。
- 我很想将它们存储为一个小单位,其中它们始终是整数:克和立方厘米。 (我知道我的包裹不会小于 1g / 1cm3)。但这对用户来说不是很友好:我的用户需要查看和输入 L (dm3) 和 kg 中的值。
我现在找到的解决方案是让列 weight_g 和 volume_cl:
rails g migration AddVolumeAndWeigthToPackageTypes volume_cm3:integer weight_g:integer
并且在我的模型中有一些在单位之间进行转换的方法:
class PackageType < ApplicationRecord
…
def volume_dm3
volume_cm3.to_f / 1000
end
def volume_dm3=(vol)
self.volume_cm3 = (vol*1000).to_i
end
def weight_kg
weight_g.to_f / 1000
end
def weight_kg=(w)
self.weight_g = (w*1000).to_i
end
end
这有效但感觉不对,并提出了几个问题:
- 为什么在 Rails 模型中我可以在没有 @ 符号的情况下访问模型属性?就像我可以通过调用 volume_cm3 而不是 self.volume_cm3 或 @volume_cm3 来读取存储的内容一样。还有为什么不把self放在前面就可以看书了,而我却需要精确self.volume_cm3才能写出来?
- 这样做是正确的方法还是我应该放弃这种转换并直接将 kg 和 L 存储为小数?我现在真的不希望以任何其他单位显示用户,kg 和 L 是我将使用的唯一单位。我很想只使用小数、kg 和 L。
- 当您需要存储具有单位的内容时,推荐的命名数据库列和模型属性的方式是什么?是"volume"(假设单位),"volume_dm3","volume_in_dm3"?
@符号是创建一个实例变量,这样控制器中的变量就可以在视图中访问。所以 @ 符号实际上与访问模型本身内的变量没有任何关系。据我所知,在写入变量时需要指定 self.volume_cm3
并且可以仅使用 volume_cm3
访问它的原因是因为在写入时,Rails 需要知道你是不要创建与属性同名的局部变量(我不推荐这样做,但我认为 ruby 不会阻止你这样做)。所以 self.volume_cm3 = 3
会设置属性 volume_cm3
,但是 volume_cm3 = 3
只会创建一个值为 3 的局部变量。
如果要将数据存储为小数,您始终可以使用 '%.Nf' % volume_cm3
对小数进行四舍五入,其中 N
是要将小数四舍五入到的位数.所以 '%.2f' % 1.345
会四舍五入到两位小数并给你 1.35
.
我认为 ruby 在数字和单位方面没有特定的命名指南,所以这可能只是一个偏好问题。如果您有其他测量体积的单位,那么将特定单位添加到属性名称的末尾可能会有所帮助,以避免混淆(例如 volume_cm3
、volume_L
等)。如果您只测量每个属性的一个单位,您可以将它们命名为 volume
和 weight
,并在模型中添加一些注释,解释它们需要使用特定的单位。
我需要在名为 PackageType 的 Rails 模型中存储一个体积和一个重量。我有两个(相关的)问题:
- 这些值可能不是整数。例如,它可能是 0.5 公斤。但我想避免与浮动相关的舍入错误:在加/乘/除后,我不想冒险得到 1.00000001kg(主要是出于会计原因)。
- 我很想将它们存储为一个小单位,其中它们始终是整数:克和立方厘米。 (我知道我的包裹不会小于 1g / 1cm3)。但这对用户来说不是很友好:我的用户需要查看和输入 L (dm3) 和 kg 中的值。
我现在找到的解决方案是让列 weight_g 和 volume_cl:
rails g migration AddVolumeAndWeigthToPackageTypes volume_cm3:integer weight_g:integer
并且在我的模型中有一些在单位之间进行转换的方法:
class PackageType < ApplicationRecord
…
def volume_dm3
volume_cm3.to_f / 1000
end
def volume_dm3=(vol)
self.volume_cm3 = (vol*1000).to_i
end
def weight_kg
weight_g.to_f / 1000
end
def weight_kg=(w)
self.weight_g = (w*1000).to_i
end
end
这有效但感觉不对,并提出了几个问题:
- 为什么在 Rails 模型中我可以在没有 @ 符号的情况下访问模型属性?就像我可以通过调用 volume_cm3 而不是 self.volume_cm3 或 @volume_cm3 来读取存储的内容一样。还有为什么不把self放在前面就可以看书了,而我却需要精确self.volume_cm3才能写出来?
- 这样做是正确的方法还是我应该放弃这种转换并直接将 kg 和 L 存储为小数?我现在真的不希望以任何其他单位显示用户,kg 和 L 是我将使用的唯一单位。我很想只使用小数、kg 和 L。
- 当您需要存储具有单位的内容时,推荐的命名数据库列和模型属性的方式是什么?是"volume"(假设单位),"volume_dm3","volume_in_dm3"?
@符号是创建一个实例变量,这样控制器中的变量就可以在视图中访问。所以 @ 符号实际上与访问模型本身内的变量没有任何关系。据我所知,在写入变量时需要指定
self.volume_cm3
并且可以仅使用volume_cm3
访问它的原因是因为在写入时,Rails 需要知道你是不要创建与属性同名的局部变量(我不推荐这样做,但我认为 ruby 不会阻止你这样做)。所以self.volume_cm3 = 3
会设置属性volume_cm3
,但是volume_cm3 = 3
只会创建一个值为 3 的局部变量。如果要将数据存储为小数,您始终可以使用
'%.Nf' % volume_cm3
对小数进行四舍五入,其中N
是要将小数四舍五入到的位数.所以'%.2f' % 1.345
会四舍五入到两位小数并给你1.35
.我认为 ruby 在数字和单位方面没有特定的命名指南,所以这可能只是一个偏好问题。如果您有其他测量体积的单位,那么将特定单位添加到属性名称的末尾可能会有所帮助,以避免混淆(例如
volume_cm3
、volume_L
等)。如果您只测量每个属性的一个单位,您可以将它们命名为volume
和weight
,并在模型中添加一些注释,解释它们需要使用特定的单位。