如何在 mysql 中存储十进制计算结果并将其检索回内存中

How to store a decimal calcaulation result in mysql and retrive it back as they were in memory

提问人:Accountant م 提问时间:3/16/2017 更新时间:3/16/2017 访问量:266

问:

MySQL文档

DECIMAL 和 NUMERIC 类型存储精确的数值数据值。当需要保持精确精度时,例如货币数据,可以使用这些类型。

我在那列上做了这个测试。decimal_column DECIMAL(31,30)

insert into tests (decimal_column) values(1/3);

然后检查存储的内容会得到这个

select * from tests ;
> result : 0.333333333000000000000000000000

然后用这个查询反转数学运算,得到这个

select decimal_column*3 from test;
> result: 0.999999999000000000000000000000

我期望得到整数“1”,因为我们在计算器和 excel 表格中这样做!喜欢这个

 #calculator or excel sheet
 >input: 1 / 3
 >result: 0.3333333333333333333333333333333333
 >input: * 3
 >result: 1

1- 为什么 MySQL 没有存储 (1 / 3) 的确切二进制表示,所以我可以在计算中再次使用该结果,因为它们像计算器或 Excel 工作表一样在内存中。

阿拉伯数字-如何在计算期间将结果存储在 mysql 中,因为它们在内存中,因此我可以检索确切的值并执行类似将 1 结果为整数之类的操作,就像我们在计算器或 excel 工作表中所做的那样。(1/3)3 * $storedValue

mysql 浮点 精度 float-accuracy

评论


答:

1赞 Ashwin Golani 3/16/2017 #1

这取决于您需要信息的内容。

如果存储用于计算和存储,请计算结果(0.33 而不是 1/3)并将其存储为十进制 (1,5)。但是,如果你想显示它,你不能轻易地向后计算它。

如果它被存储为以后显示,但永远不会再次修改(或至少不快速),您可以将其存储为 varchar,但这会破坏排序。

或者您可以存储不同的元素(正数、负数、总数......whatever)作为十进制(5,0)并在使用它时显示/计算它。

当然,如果您想在选择时从计算时间中获得优势,您可以结合上述内容。

1赞 O. Jones 3/16/2017 #2

MySQL 使用 64 位 IEEE 754 浮点数进行内部分数运算。

它们通常是近似值。期望IEEE浮点数或十进制算术在执行时实现完全相等是完全不合理的

   3*(1/3) == 1

这不是计算机算术的工作方式。

也没有办法存储值 1/3 的精确表示,除非您碰巧使用以(分子,分母)对的形式存储有理数(小数)的奇特计算系统。MySQL不是这样的系统。

大多数计算器将其结果隐式舍入到它们可以显示的位数。Excel 也包含一个格式模块。您可以通过按 -1 来选择单元格的格式。格式化模块对这些浮点数进行舍入。您可以使用 ROUND() 函数在 MySQL 中实现相同的效果。该函数不会更改存储的值,但它确实以隐藏 IEEE 754 浮点运算中固有的微小错误的方式呈现它。

SELECT ROUND(decimal_column, 2) AS decimal_column

(会计人员不是必须在学校里学习这些东西吗?

评论

0赞 Accountant م 3/16/2017
所以,当我在计算器上做时,然后将结果乘以 3,计算器给我 1 .这是否意味着这个 1 与我开始计算时使用的整数 1 值不完全相同?它更像是?1/3*31.0000000000000000000000000000000000000000001
0赞 Accountant م 3/16/2017
“会计人员不是必须在学校里学习这些东西吗?”不,他们没有。浮点数在二进制系统中的表示方式超出了会计范围。它甚至仍然让一些程序员感到困惑。
1赞 LSerni 3/16/2017 #3

问题不在于存储。在您的示例中,该值在存储到表中之前已损坏。

不幸的是,如果你写 1/3,它将使用默认表示进行计算(并插入):

SELECT 1/3

0.333333333

如您所见,其精度不足。

另一个问题是,当您向服务器发送常量(1 或 3)时,您需要使用连接器来执行此操作,这可以自由使用该值。例如,它可能认为“1”和“3”是整数,它们的结果将被视为整数。因此,您得到“1/3 = 0”,但“1./3 = 0.333333”,因为“1.”中的点使连接器意识到它需要使用其默认浮点。而且你只得到六个 3,因为连接器的“默认浮点数”有 6 位数字。然后将其存储到数据库中,但为时已晚。您正在以高精度存储已被截断为低精度的值。

您可以尝试从一开始就强制转换常量。使用“1”而不是“1”,而是将 1 转换为足够大的小数点。我在这里使用你的 31,30,但请检查您是否不需要存储更大的数字。可能,“31,20”会更好。

mysql> SELECT 1/3 UNION SELECT CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+----------------------------------+
| 1/3                              |
+----------------------------------+
| 0.333333333000000000000000000000 |
| 0.333333333333333333333333333333 |
+----------------------------------+
2 rows in set (0.00 sec)

这很尴尬,但结果应该更好。另外,我认为只需要在表达式中强制转换一个值;然后,MySQL将根据需要提升所有涉及的数量。因此,将 CAST(0 AS DECIMAL(x,y)) 添加到总和中,将 CAST(1 AS DECIMAL(x,y)) 添加到乘法中可能就足够了。

mysql> SELECT 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+-------------------------------------------------------+
| 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30)) |
+-------------------------------------------------------+
|                      1.000000000000000000000000000000 |
+-------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT CAST(1 AS DECIMAL(31,30))*1/3;
+----------------------------------+
| CAST(1 AS DECIMAL(31,30))*1/3    |
+----------------------------------+
| 0.333333333333333333333333333333 |
+----------------------------------+
1 row in set (0.00 sec)

请注意,不起作用,因为乘法具有更高的优先级:

mysql> SELECT CAST(0 AS DECIMAL(31,30))+1/3;
+----------------------------------+
| CAST(0 AS DECIMAL(31,30))+1/3    |
+----------------------------------+
| 0.333333333000000000000000000000 |
+----------------------------------+
1 row in set (0.00 sec)

评论

0赞 Accountant م 3/16/2017
谢谢。但仍然有一些让我感到困惑的地方。为什么当我在 excel 工作表中做 1/3 然后将结果乘以 3 时。当我格式化结果“1”以显示我仍然看到的十进制数时,我得到“1”(1.000000000000000....)对于超过 70 位数字,根本没有分数,全部为零。!
1赞 LSerni 3/16/2017
Excel 有几个格式设置“有用”的技巧 - 它让你看到的不是“内部”的内容。它试图“理解”。例如,16/1/16 在算术中实际上是 1 - 在我的 Excel 副本中是 2016 年 1 月 16 日。16/1/16+1 不是 2,而是 46250 左右——自我不记得日期以来的儒略日数。在其他情况下,Excel 将“纠正”它认为的舍入错误......不管这是否是正确的做法。总而言之:不要以Excel(或任何其他[Microsoft]程序)为例来说明数学(或程序员的数学)应该如何工作
0赞 Accountant م 3/16/2017
哎呀,这么多年使用计算器,我一直在想,当我这样做时,然后反转这个过程,我得到的和我开始的 1 一样。非常感谢您抽出时间接受采访。我将饶有兴趣地阅读该浮点指南。1/3result * 3