何时使用float和decimal?

23

我正在构建这个API,数据库将存储代表以下之一的值:

  • 百分比
  • 平均数
  • 比率

老实说,我不知道如何用数字表示范围在0到100%之间的内容。应该是

  • 0.00-1.00
  • 0.00-100.00
  • 我不知道的其他任何替代方案

有没有明确的选择? 全球通用的数据库表示0到100%的方式是什么? 此外,它的正确类型是float还是decimal?

谢谢。


3
这个问题的答案是否能够解决你的疑问?(存储统计数据时,我需要使用 DECIMAL、FLOAT 还是 DOUBLE?) - Marty
5
数字可以以许多方式存储。使用0-100或0-1存储百分比都没有本质上的问题。重要的是你需要对数字进行什么操作,需要什么精度等。在提供良好答案之前,您必须解释更多的上下文信息。您是否需要存储可以用少量小数位表示的数字?如果你要对一些东西取平均值,你会得到像三分之一或七分之一这样的分数。您需要准确地存储它们吗?或者只是近似地存储?近似到什么程度?您将如何处理它们? - Eric Postpischil
1
如果值在0.00到100.00之间,步长为0.01,那么就有10001个不同的值。只需使用一个“int”来表示百分之一或万分之一的单位。 - chux - Reinstate Monica
@chux-ReinstateMonica - 是的,“缩放整数”是可能的,但很笨拙。 - Rick James
@RickJames 或许吧。我觉得缩放整数并不难。 - chux - Reinstate Monica
7个回答

10
我将持相反立场。
FLOAT用于近似数字,例如百分比、平均值等。你应该在显示值时进行格式化,可以在应用程序代码中或使用MySQL的FORMAT()函数。
永远不要测试float_value = 1.3;这会导致失败的原因很多。
DECIMAL应用于货币价值。DECIMAL避免了当需要将值舍入到美元/美分/欧元等时的第二次舍入。会计师不喜欢几分钱。
MySQL的实现允许65个有效数字;FLOAT大约有7个,DOUBLE大约有16个。 7通常对传感器和科学计算而言足够了。
至于“百分比”,有时我使用TINYINT UNSIGNED,当我只想使用1字节的存储并且不需要太高精度时;有时我使用FLOAT(4字节)。没有专门针对百分比调整的数据类型。(还请注意,DECIMAL(2,0)无法保留值100,因此您需要DECIMAL(3,0))。
有时我用一个FLOAT来存储0到1之间的值。但是我需要确保在显示“百分比”之前乘以100。
更多
“百分比,平均率”都像浮点数一样,所以这将是我的首选。
决定数据类型的一个标准是...该值将存在多少个副本?
如果您有一个10亿行的表,其中包含百分比列,则考虑TINYINT将占用1字节(总共1 GB),但FLOAT将占用4字节(总共4 GB)。不过,大多数应用程序并没有那么多的行,因此这可能无关紧要。
作为“通用”规则,“精确”的值应使用某种形式的INT或DECIMAL。不精确的事物(科学计算、平方根、除法等)应使用FLOAT(或DOUBLE)。
此外,输出的格式通常应保留给应用程序前端。也就是说,即使“平均值”计算为“14.6666666...”,显示也应该显示类似于“14.7”的内容;这对人类来说更友好。同时,您可以拥有底层的值以稍后决定“15”或“14.667”是更合适的输出格式。

范围“0.00-100.00”可以使用FLOAT和输出格式化,或者使用DECIMAL(5,2)(3字节)进行处理,并预先确定您始终需要指定的精度。


3
我一般不建议使用浮点数(float)。浮点数是以二进制表示数字的,这导致某些(精确的)数字在运算或比较时会被四舍五入,因为它们无法准确地以二进制进行存储。这可能导致出现令人惊讶的行为。
考虑以下示例: 点击此处查看
create table t (num float);
insert into t values(1.3);

select * from t;

| num |
| --: |
| 1.3 |

select * from t where num = 1.3;

| num |
| --: |

使用二进制比较数字1.3会失败,这很棘手。

相比之下,十进制提供了其范围内有限数字的准确表示。如果在上述示例中将float更改为decimal(2, 1),则可以得到预期结果。


4
这个答案在几个方面是错误的。“相比之下,小数具有更小的范围,但可以提供该范围内有限数字的精确表示”是错误的:十进制不能精确表示1/3。“一些(确切的、有限的)数字被四舍五入”是不正确的;数字不会“被四舍五入”。转换和其他操作可能会进行四舍五入。默认的舍入模式最常见的是四舍六入五留双,而不是向上取整。 - Eric Postpischil
4
精度问题与“浮点数”无关,而是由数字表示本身引起的: 所有有限数字表示都有精度限制:浮点数、定点数、整数、有理数、小数、二进制、一切。 - Eric Postpischil
2
叹气。你修复了什么?我的评论说答案是错误的,因为它说十进制在其范围内提供数字的精确表示,但实际上它不提供⅓的精确表示。更改将“精确”更改为“准确”,但是二进制浮点数为什么不一样好 - 两者都对⅓不精确,取决于准确度的阈值以及它们具有多少精度,它们都是准确或不准确的。问题指出将表示平均值,并且平均三个物品会给出像⅓这样的数字。 - Eric Postpischil
4
评论说最常用的是四舍五入到偶数,但回答中仍然说向上取整。回答说比较可能会向上取整,但比较是完美的:比较始终返回一个数学上正确的结果,没有进行任何近似处理。(一些编程语言在比较之前可能会转换操作数,但这是单独的操作。) - Eric Postpischil
1
1/3 在二进制或十进制中都无法被 精确地 表示。14.99 美元的 20% 折扣需要四舍五入,因为不存在分数美分。 - Rick James
显示剩余4条评论

1

如果您要以与显示相同的方式存储数据,我建议使用decimal(5,2),因为decimal可以保留精确度。(请参见https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html)

由于浮点数是近似值,而不是精确值,因此在比较中试图将它们视为精确值可能会导致问题。它们也受平台或实现依赖性的影响。

(https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html)

在SQL语句中写入的浮点数值可能与内部表示的值不同。对于DECIMAL列,MySQL使用65位小数精度执行操作,这应该解决大多数常见的不准确问题。

https://dev.mysql.com/doc/refman/8.0/en/problems-with-float.html


1

十进制数: 在金融应用中,最好使用十进制类型,因为它可以提供高精度并且容易避免舍入误差。

双精度浮点数: 双精度浮点数是除了处理货币之外最常用的实数数据类型。

单精度浮点数: 它主要用于图形库中,因为需要很高的处理能力,并且用于可以容忍舍入误差的情况。

参考资料:http://net-informations.com/q/faq/float.html


0

浮点数和十进制数之间的区别在于精度。在十进制格式的精度范围内,十进制数可以100%准确地表示任何数字,而浮点数不能准确地表示所有数字。

对于与财务相关的值,请使用十进制数;对于图形相关的值,请使用浮点数。


0
在T-SQL中: Float类型,0.0会被存储为0,不需要在小数点后面定义数字位数,例如不需要写成Float(4,2)。 Decimal类型,0.0会被存储为0.0,并且可以定义像decimal(4,2)这样的选项。我建议使用0.00-1.00,这样你就可以计算出该百分比的值,而无需乘以100。如果你要报告数据,则将该列的数据类型设置为像MS Excel和其他平台视图中的“百分比”一样的格式,如0.5 -> 50%

0
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G

*********************************************************************

@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100

在这些情况下,十进制小数正好做到了它应该做的事情,截断了其余部分,因此失去了1/3的部分。

所以对于求和,十进制小数更好,但对于除法,浮点数更好,当然,在某个程度上是这样。我的意思是,使用DECIMAL不能以任何方式给您“失误防护算术”。

希望这能有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接