具有非整數的模運算符 - 意外結果
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 .1
,col % .1
因此它與計算而不是語義有關。將此與 Oracle 的行為(如果重要,使用 SQL Developer)進行比較,其中的類型
col
為NUMBER
: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。
簡而言之,浮點算術類型,如
float
和double
mysql 類型永遠不應該用於精確算術。而你col mod 0.1
正試圖做到這一點,一個精確的算術檢查。它試圖找出 in 的值col
是否是 的精確倍數0.1
。它失敗得很慘,從你的結果中可以明顯看出。**解決方法是使用固定類型,比如
decimal(m, n)
**做這些類型的檢查。至於為什麼你在 Oracle 中得到不同的結果,那是因為你使用了
NUMBER
不同的實現方式(十進制精度)。在 Oracle 中 float 和 double 的等價物是BINARY_FLOAT
andBINARY_DOUBLE
並且使用二進制精度。請參閱 Oracle 文件中的註釋:數值數據類型概述:Oracle 數據庫提供了兩種專門用於浮點數的數值數據類型:
BINARY_FLOAT
和BINARY_DOUBLE
. 它們支持NUMBER
數據類型提供的所有基本功能。但是,雖然**NUMBER
使用十進制精度**,BINARY_FLOAT
而BINARY_DOUBLE
使用二進制精度。這可以實現更快的算術計算,並且通常會降低儲存需求。注意:
BINARY_DOUBLE
並BINARY_FLOAT
實施大多數電氣和電子工程師協會 (IEEE) 二進制浮點算術標準,IEEE 標準 754-1985 (IEEE754)。如果您堅持使用
double
(我看不出為什麼),mod
在 mysql 中使用操作符/函式進行更多測試表明:當您使用整數作為參數時,假設您使用
x mod K
,結果始終是 和 之間的0
整數K-1
。預期的數學行為。當您使用浮點數/雙精度數時,假設您這樣做
x mod K
,結果是從0.0
到K
include的任何數字。(作為您的測試5850.0 mod 0.1
結果顯示0.1
)。我還沒有做過數百萬次測試,所以在某些情況下結果甚至可能大於K
!浮點運算會產生奇怪的結果。因此,一種解決方法(可能並不總是有效!)將使用此條件:
( mod(col, 0.1) <> 0.0 AND mod(col, 0.1) <> 0.1 )
老實說,我什至提出了解決方法的建議,我感到很難過。請再次閱讀**每個程序員應該知道的關於浮點運算的知識**,不要使用解決方法。
使用固定精度類型進行精度算術運算。