MySQL MOD() 坏了:这是最好的选择吗?
MySQL MOD() is broken: Is this the best alternative?
至少在 MySQL v5.1.73 (CentOS 6.6) 中,MOD() 函数 returns 是一个伪造的结果……除非有人能解释这实际上是如何正确的。
mysql> select MOD(-385.4784399 ,1440);
+-------------------------+
| MOD(-385.4784399 ,1440) |
+-------------------------+
| -385.4784399 |
+-------------------------+
1 row in set (0.01 sec)
这是最好的选择吗?
mysql> select -385.478439885319 - 1440 * FLOOR(-385.478439885319/1440);
+----------------------------------------------------------+
| -385.478439885319 - 1440 * FLOOR(-385.478439885319/1440) |
+----------------------------------------------------------+
| 1054.521560114681 |
+----------------------------------------------------------+
1 row in set (0.00 sec)
我认为这也会起作用,但是做一些简单的事情需要很长的路要走。
mysql> select MOD((MOD(-385.478439885319, 1440) + 1440), 1440);
+--------------------------------------------------+
| MOD((MOD(-385.478439885319, 1440) + 1440), 1440) |
+--------------------------------------------------+
| 1054.521560114681 |
+--------------------------------------------------+
1 row in set (0.00 sec)
MySQL 不会给你一个虚假的结果,它只是使用了与你预期不同的模数实现。不幸的是,术语模数的定义似乎有些含糊不清,而且它的实现因语言而异。据我所知,在 Wikipedia on Modulo 中,MySQL 的实现使用了 截断除法 :
r = a - n * trunc(a / n)
您希望实现使用的地方 floored division:
r = a - n * floor(a / n)
由于这是您实施第一个解决方法的方式,我想说它可能是 Mod
运算符的最佳替代方案。
据我所见(这是一个非常快速的不科学分析!),似乎更多的命令式编程语言实现了截断除法,而更多的函数式数学语言似乎实现了使用 底除法 .
至少在 MySQL v5.1.73 (CentOS 6.6) 中,MOD() 函数 returns 是一个伪造的结果……除非有人能解释这实际上是如何正确的。
mysql> select MOD(-385.4784399 ,1440);
+-------------------------+
| MOD(-385.4784399 ,1440) |
+-------------------------+
| -385.4784399 |
+-------------------------+
1 row in set (0.01 sec)
这是最好的选择吗?
mysql> select -385.478439885319 - 1440 * FLOOR(-385.478439885319/1440);
+----------------------------------------------------------+
| -385.478439885319 - 1440 * FLOOR(-385.478439885319/1440) |
+----------------------------------------------------------+
| 1054.521560114681 |
+----------------------------------------------------------+
1 row in set (0.00 sec)
我认为这也会起作用,但是做一些简单的事情需要很长的路要走。
mysql> select MOD((MOD(-385.478439885319, 1440) + 1440), 1440);
+--------------------------------------------------+
| MOD((MOD(-385.478439885319, 1440) + 1440), 1440) |
+--------------------------------------------------+
| 1054.521560114681 |
+--------------------------------------------------+
1 row in set (0.00 sec)
MySQL 不会给你一个虚假的结果,它只是使用了与你预期不同的模数实现。不幸的是,术语模数的定义似乎有些含糊不清,而且它的实现因语言而异。据我所知,在 Wikipedia on Modulo 中,MySQL 的实现使用了 截断除法 :
r = a - n * trunc(a / n)
您希望实现使用的地方 floored division:
r = a - n * floor(a / n)
由于这是您实施第一个解决方法的方式,我想说它可能是 Mod
运算符的最佳替代方案。
据我所见(这是一个非常快速的不科学分析!),似乎更多的命令式编程语言实现了截断除法,而更多的函数式数学语言似乎实现了使用 底除法 .