Datatypes

具有非整數的模運算符 - 意外結果

  • July 30, 2015

MySQL 5.5.32、甲骨文 11g

mod()對於涉及非整數模數的查詢,MySQL 返回奇怪的結果。為什麼是這樣?

我有一個這樣定義的列:

+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| col    | double(15,6) | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+

我從該列中選擇了一個已知值用於測試 - 5850。如果我查詢表,測試該列的整數,我得到以下結果:

mysql> SELECT thing_id,name FROM table WHERE col=5850 AND mod(col,1) != 0;
Empty set (1.07 sec)

這是意料之中的。但這不是:

mysql> SELECT thing_id,name FROM table WHERE col=5850 AND mod(col,.1) != 0;
+-----------+-----------+
| thing_id  | name      |
+-----------+-----------+
|   4444444 | some      |
|   4444445 | names     |
...
|  55555555 | go        |
|  55555556 | here      |
+-----------+-----------+
416 rows in set (1.07 sec)

替換的結果相同col MOD .1col % .1因此它與計算而不是語義有關。

將此與 Oracle 的行為(如果重要,使用 SQL Developer)進行比較,其中的類型colNUMBER

SELECT thing_id,name FROM table WHERE col=5850 AND mod(col,.1) != 0;
thing_id    name
[NO RECORDS]

MySQL 列上的精度似乎造成了這種差異,但我不明白如何。從概念上講,不應該integer_value % .1 = 0嗎?

我將從一個連結開始:What Every Programmer Should Know About Floating-Point Arithmetic

簡而言之,浮點算術類型,如floatdoublemysql 類型永遠不應該用於精確算術。而你col mod 0.1正試圖做到這一點,一個精確的算術檢查。它試圖找出 in 的值col是否是 的精確倍數0.1。它失敗得很慘,從你的結果中可以明顯看出。

**解決方法是使用固定類型,比如decimal(m, n)**做這些類型的檢查。

至於為什麼你在 Oracle 中得到不同的結果,那是因為你使用了NUMBER不同的實現方式(十進制精度)。在 Oracle 中 float 和 double 的等價物是BINARY_FLOATandBINARY_DOUBLE並且使用二進制精度。請參閱 Oracle 文件中的註釋:數值數據類型概述

Oracle 數據庫提供了兩種專門用於浮點數的數值數據類型:BINARY_FLOATBINARY_DOUBLE. 它們支持NUMBER數據類型提供的所有基本功能。但是,雖然**NUMBER使用十進制精度**,BINARY_FLOATBINARY_DOUBLE使用二進制精度。這可以實現更快的算術計算,並且通常會降低儲存需求。

注意:

BINARY_DOUBLEBINARY_FLOAT實施大多數電氣和電子工程師協會 (IEEE) 二進制浮點算術標準,IEEE 標準 754-1985 (IEEE754)。


如果您堅持使用double(我看不出為什麼),mod在 mysql 中使用操作符/函式進行更多測試表明:

當您使用整數作為參數時,假設您使用x mod K,結果始終是 和 之間的0整數K-1。預期的數學行為。

當您使用浮點數/雙精度數時,假設您這樣做x mod K,結果是從0.0K include的任何數字。(作為您的測試5850.0 mod 0.1結果顯示0.1)。我還沒有做過數百萬次測試,所以在某些情況下結果甚至可能大於K!浮點運算會產生奇怪的結果。

因此,一種解決方法(可能並不總是有效!)將使用此條件:

( mod(col, 0.1) <> 0.0  AND  mod(col, 0.1) <> 0.1 )

老實說,我什至提出了解決方法的建議,我感到很難過。請再次閱讀**每個程序員應該知道的關於浮點運算的知識**,不要使用解決方法。

使用固定精度類型進行精度算術運算。

引用自:https://dba.stackexchange.com/questions/108577