如何将小数计算结果存储在 mysql 中,并在内存中将其取回
How to store a decimal calcaulation result in mysql and retrive it back as they were in memory
MySQL 文档 says :
The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision, for example with monetary data.
我在该列上做了这个测试 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 sheet 中所做的那样!像这样
#calculator or excel sheet
>input: 1 / 3
>result: 0.3333333333333333333333333333333333
>input: * 3
>result: 1
1- 为什么 MySQL 没有存储 (1 / 3) 的精确二进制表示,所以我可以在我的计算中再次使用该结果在内存中像计算器或 excel sheet.
2- 如何在 mysql 中存储 (1/3)
的结果,因为它们在计算期间在内存中,所以我可以检索准确的返回值并执行类似 3 * $storedValue
的操作以得到 1 作为整数,就像我们在计算器中所做的那样或 excel sheet.
这取决于您需要这些信息的目的。
如果存储是为了计算和存储,则计算结果(0.33而不是1/3)并将其存储为小数(1,5)。但是要显示的话就不能轻易倒过来计算了。
如果将其存储为稍后显示但永远不会再次修改(或至少不会很快),您可以将其存储为 varchar,但这会破坏排序。
或者您可以将不同的元素(正数、负数、总计等)存储为 decimal(5,0) 并在使用时显示/计算它。
当然,如果你想在选择时得到计算时间的优势,你可以结合上面的方法。
MySQL 使用 64-bit IEEE 754 floating point 个数字进行内部小数运算。
它们通常是近似值。期望 IEEE 浮点数或十进制算术在执行
时实现完全相等是完全不合理的
3*(1/3) == 1
这不是计算机运算的方式。
也没有办法存储值 1/3 的精确表示,除非您碰巧使用以(分子,分母)对的形式存储有理数(小数)的奇异计算系统。 MySQL 不是这样的系统。
大多数计算器都会隐式地将结果四舍五入到它们可以显示的位数。 Excel,也包含一个格式化模块。您可以按 -1 选择单元格的格式。格式化模块舍入这些浮点数。您可以使用 ROUND() function 在 MySQL 中实现相同的效果。该函数不会更改存储的值,但它确实以一种隐藏 IEEE 754 浮点运算中固有的微小错误的方式呈现它。
SELECT ROUND(decimal_column, 2) AS decimal_column
(会计不是必须在学校学这些东西吗?)
问题不在存储中。在您的示例中,该值在存储到 table.
之前被破坏了
不幸的是,如果您写 1/3,将使用默认表示法计算(并插入):
SELECT 1/3
0.333333333
如您所见,精度不够。
另一个问题是,当您向服务器发送常量(1 或 3)时,您需要使用 library 或 connector,可以随意取值。例如,它可能认为“1”和“3”是整数,并且它们的结果将被视为整数。所以你得到“1/3 = 0”,但是“1./3 = 0.333333”,因为“1”中的点。使连接器意识到它需要使用其默认浮点数。你只得到六个 3,因为连接器的 "default floating point" 有 6 个数字。然后将其存储到数据库中,但是为时已晚。您正在以高精度存储一个已被截断为低精度的值。
您可以尝试从头开始转换常量。您可以使用 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)
很别扭,不过效果应该会更好。另外,我认为只需要在表达式中转换 one 值; 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)
MySQL 文档 says :
The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision, for example with monetary data.
我在该列上做了这个测试 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 sheet 中所做的那样!像这样
#calculator or excel sheet
>input: 1 / 3
>result: 0.3333333333333333333333333333333333
>input: * 3
>result: 1
1- 为什么 MySQL 没有存储 (1 / 3) 的精确二进制表示,所以我可以在我的计算中再次使用该结果在内存中像计算器或 excel sheet.
2- 如何在 mysql 中存储 (1/3)
的结果,因为它们在计算期间在内存中,所以我可以检索准确的返回值并执行类似 3 * $storedValue
的操作以得到 1 作为整数,就像我们在计算器中所做的那样或 excel sheet.
这取决于您需要这些信息的目的。
如果存储是为了计算和存储,则计算结果(0.33而不是1/3)并将其存储为小数(1,5)。但是要显示的话就不能轻易倒过来计算了。
如果将其存储为稍后显示但永远不会再次修改(或至少不会很快),您可以将其存储为 varchar,但这会破坏排序。
或者您可以将不同的元素(正数、负数、总计等)存储为 decimal(5,0) 并在使用时显示/计算它。
当然,如果你想在选择时得到计算时间的优势,你可以结合上面的方法。
MySQL 使用 64-bit IEEE 754 floating point 个数字进行内部小数运算。
它们通常是近似值。期望 IEEE 浮点数或十进制算术在执行
时实现完全相等是完全不合理的 3*(1/3) == 1
这不是计算机运算的方式。
也没有办法存储值 1/3 的精确表示,除非您碰巧使用以(分子,分母)对的形式存储有理数(小数)的奇异计算系统。 MySQL 不是这样的系统。
大多数计算器都会隐式地将结果四舍五入到它们可以显示的位数。 Excel,也包含一个格式化模块。您可以按 -1 选择单元格的格式。格式化模块舍入这些浮点数。您可以使用 ROUND() function 在 MySQL 中实现相同的效果。该函数不会更改存储的值,但它确实以一种隐藏 IEEE 754 浮点运算中固有的微小错误的方式呈现它。
SELECT ROUND(decimal_column, 2) AS decimal_column
(会计不是必须在学校学这些东西吗?)
问题不在存储中。在您的示例中,该值在存储到 table.
之前被破坏了不幸的是,如果您写 1/3,将使用默认表示法计算(并插入):
SELECT 1/3
0.333333333
如您所见,精度不够。
另一个问题是,当您向服务器发送常量(1 或 3)时,您需要使用 library 或 connector,可以随意取值。例如,它可能认为“1”和“3”是整数,并且它们的结果将被视为整数。所以你得到“1/3 = 0”,但是“1./3 = 0.333333”,因为“1”中的点。使连接器意识到它需要使用其默认浮点数。你只得到六个 3,因为连接器的 "default floating point" 有 6 个数字。然后将其存储到数据库中,但是为时已晚。您正在以高精度存储一个已被截断为低精度的值。
您可以尝试从头开始转换常量。您可以使用 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)
很别扭,不过效果应该会更好。另外,我认为只需要在表达式中转换 one 值; 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)