MySQLã®FLOATåã使ãçç±ãè¦ã¤ãããªã件
MySQLã®ãã¼ã¿åã¨ãã¦FLOATåã¨ããåãããã®ã§ããããããæ¡ç¨ããã®ã¯æ··ä¹±ã®å ã§ã¯ãªããï¼ã¨æããã®ã§ããã®è©³ç´°ãç´¹ä»ãã¾ãã
ãããããã®è©±ã®ãã£ããã¯ãMySQLで6桁までの小数点を丸めずに扱うならFLOAT型を使うべき理由ãã¨ããè¨äºãç®ã«æ¢ã¾ã£ããã¨ã§ãããããªãã«äººæ°ãéãã¦ããè¨äºã®ããã§ãããç§ã®èªãã éãã§ã¯FLOATåã使ãã ãã®æ ¹æ ãæä¸ããèªã¿åãããããã«é¡ä¼¼ããä¸æ¬¡æ å ±ãè±èªè¨äºãå ¨ãè¦ã¤ãããªãã£ãã®ã§ãçå½ãæªããæ å ±ã ã¨æãã¾ããã
ãã®å¾ãMySQLä¸ã§å®é¨ãããCã½ã¼ã¹ã³ã¼ããèªãã§ã¿ããããçµæãç§ã®å¾ãçµè«ã¯çéã®ãã®ã«ãªãã¾ãããMySQLè¦å¯ã®æ¹ãæµ®åå°æ°ç¹æ°è¦å¯ã®æ¹ã追試ãåè«ãªã©é ããã¨å©ããã¾ãã
MySQLã®FLOATåã¨ã¯
MySQLã®FLOATåã¯ååã¨ãã¦IEEE754æµ®åå°æ°ç¹æ°å精度åï¼32bitï¼ã§å®ç¾ããã¾ã*1ãããèªä½ã¯MySQLããã¥ã¢ã«ãããèªã¿åããå
容ã§ãã
FLOAT ããã³ DOUBLE åã¯æ¦æ°å¤ãã¼ã¿å¤ã表ãã¾ããMySQL ã¯ãå精度å¤ã«ã¯ 4 ãã¤ãããå精度å¤ã«ã¯ 8 ãã¤ãã使ç¨ãã¾ãã
https://dev.mysql.com/doc/refman/5.6/ja/floating-point-types.html
ååã¨ãã¦ãCè¨èªã®floatåã«å¯¾å¿ãã¦ããããªååã§ããããããèªä½ã«ç¹ã«éåæã¯ç¡ãã¨è¨ããã§ãããã
ä¸æè°ãªæå(1)ï¼+0ããã¨è¦ãç®ã®å¤ãå¤ãã
ã¨ããã§ãMySQLã§FLOATåã使ãã¨èª¬æãã¥ããçµæã«ãªããã¨ãããã¾ããå®éã«è©¦ãã¦ã¿ã¾ããããä¸è¨å®é¨ã«å©ç¨ããMySQLã®ãã¼ã¸ã§ã³ã¯5.7.20ã§ãã
mysql> CREATE TABLE a (f FLOAT, d DOUBLE); Query OK, 0 rows affected (0.03 sec) mysql> INSERT INTO a VALUES(0.9,0.9); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM a; +------+------+ | f | d | +------+------+ | 0.9 | 0.9 | +------+------+ 1 row in set (0.00 sec)
FLOATåã¨DOUBLEåã®ã«ã©ã ãä½ãã両è
ã«0.9ã代å
¥ãã¦ã¿ã¾ãããSELECTãã¦ã¿ãã¨ãããããã®ã«ã©ã ã®å¤ã¯0.9ã¨è¡¨ç¤ºããã¾ãã
ã¨ããããããããã«0ã足ãã¨ä¸æè°ãªçµæãè¿ã£ã¦ãã¾ãã
mysql> SELECT f+0,d+0 FROM a; +--------------------+------+ | f+0 | d+0 | +--------------------+------+ | 0.8999999761581421 | 0.9 | +--------------------+------+ 1 row in set (0.00 sec)
ãªãã¨FLOATåã®å¤ã®æ¹ã0.9ã§ã¯ç¡ããªã£ã¦ãã¾ãã¾ãããããã¯+0ããããã§å¤ãå¤ãã£ãããã§ã¯ãªããå
ã
æ ¼ç´ããã¦ããå¤ã表示ããã¦ããã ãã§ããã0.8999999761581421â¦ãã¯IEEE754å精度浮åå°æ°ç¹æ°ã§0.9ã«ä¸çªè¿ãæ°ã§ãã®ã§ãFLOATåã§ã¯å精度ã§å¤ãä¿åããã¦ãã証æ ã¨ãè¨ããã§ãããã
ä¸æ¹ãd+0ã0.9ã¨è¡¨ç¤ºããã¦ããã®ã¯dã®å¤ãå精度浮åå°æ°ç¹æ°ã§0.9ã«ä¸çªè¿ãæ°ã ããã§ããMySQLã¯DOUBLEåã®å¤ã表示ããéãåãå¾ã表ç¾ã®ä¸ã§æçã¨ãªã10é²è¡¨ç¾ã§è¡¨ç¤ºãã¾ãããã®ãã¨ã¯MySQLããã¥ã¢ã«ã«ãè¨è¿°ãããã¾ãã
dtoa ã©ã¤ãã©ãªã§ã¯ã次ã®ããããã£ã¼ã使ç¨ããå¤æãæä¾ããã¾ããD 㯠DECIMAL ã¾ãã¯æåå表ç¾ãå«ãå¤ã表ããF ã¯ãã¤ãã£ããã¤ã㪠(IEEE) æ¸å¼ã®æµ®åå°æ°ç¹æ°ã表ãã¾ãã
F -> D ã®å¤æã¯ãæ大éã®ç²¾åº¦ã§å®è¡ãããèªã¿åãæã« F ãçæããããã£ã¨ãçãæååã¨ã㦠D ãè¿ãããIEEE ã§æå®ããã¦ãããã¤ãã£ããã¤ããªå½¢å¼ã§ãã£ã¨ãè¿ãå¤ã«ä¸¸ãããã¾ãã
https://dev.mysql.com/doc/refman/5.6/ja/type-conversion.html
ãããªããã§ã10é²å°æ°ãæ ¼ç´ããå ´åã«ã¯FLOATåãDOUBLEåã丸ã誤差ãå«ãå¤ã«ãªãã®ã§ãããæåã«ç´¹ä»ããQiitaè¨äºã®èªè
ããããèªã¿åãããã¯çåã§ãããããããã¨FLOATåã®ãã¨ã10é²6æ¡ã¾ã§ãããã¿ãªæ±ãã便å©ãªåã ã¨åéããã¦ãã¾ã人ããããããç¥ãã¾ãããããããªããã¯ããã¾ããã
ä¸æè°ãªæå(2)ï¼INSERTããå¤ãWHEREå¥ã®æ¤ç´¢æ¡ä»¶ã«ä½¿ããªã
å
ã»ã©ã®ãã¼ãã«ã使ã£ã¦ããå°ãå®é¨ãã¦ã¿ã¾ããä»åº¦ã¯WHEREå¥ã§æµ®åå°æ°ç¹åãæã¤ã¬ã³ã¼ããæ¤ç´¢ãã¦ã¿ã¾ãããã
mysql> SELECT * FROM a WHERE f=0.9; Empty set (0.00 sec) mysql> SELECT * FROM a WHERE d=0.9; +------+------+ | f | d | +------+------+ | 0.9 | 0.9 | +------+------+ 1 row in set (0.00 sec)
fãdãINSERTæã§0.9ãå
¥ããã®ã§ãå½ç¶WHEREå¥ã®æ¤ç´¢ã§ã0.9ã使ããã ããã¨èãã人ãããããããã¾ãããã¨ããããå®éã«0.9ãæ¤ç´¢ãã¦ã¿ãã¨FLOATåã®æ¹ã§ã¯1件ãããããã¾ããã
ãã®åå ã¯ãæµ®åå°æ°ç¹æ°çµ¡ã¿ã®æ¼ç®ã¯å ¨ã¦DOUBLEåã§è¨ç®ããããã*2ã§ããfã®å¤ã¯ã0.8999999761581421â¦ãã¨ãªãã¾ãããDOUBLEåã¨ãã¦ã®0.9ã¯ã0.900000000000000022â¦ãã¨ãªããããç°ãªãå¤ã ã¨å¤æããã¦ãã¾ãã®ã§ããä¸æ¹ã§ãDOUBLEåã®ã«ã©ã ã¯INSERTãSELECTãå ¨ã¦DOUBLEåã§è¡ãããã®ã§ãæå¾ éãã«ã¬ã³ã¼ããåãåºããã¨ãã§ãã¾ãã
ã©ããã¦ãFLOATåã®å¤ãæ¤ç´¢ã§å¼ã£ããããå ´åã¯ã欲ããFLOATåã®å¤ãDOUBLEåã«ãã£ã¹ãããã¨ãã®æµ®åå°æ°ç¹æ°ãªãã©ã«ã渡ãå¿
è¦ãããã¾ããå®ç¨çã¨ã¯è¨ããããã§ããã
mysql> SELECT * FROM a WHERE f=0.8999999761581421; +------+------+ | f | d | +------+------+ | 0.9 | 0.9 | +------+------+ 1 row in set (0.00 sec)
ã¾ã¨ããã¨ãMySQLã§ã¯å¤ãã®æµ®åå°æ°ç¹æ¼ç®ãDOUBLEåã§è¡ãããã®ã§ãFLOATåã®å©ç¨ã«ã¯æ³¨æãå¿
è¦ã§ããFLOATåããDOUBLEåã¸ã®ãã£ã¹ãã®æ§è³ªã«ãã³ã¨ããªã人ãå©ç¨ããã¨æ··ä¹±ãã¦ãã¾ãããããã¾ããã
ä¸æè°ãªæå(3)ï¼åãå¤ã«è¦ãã¦ãå¥ã®å¤ã®ãã¨ããã
ããã«å¥ã®ä¾ãç´¹ä»ãã¾ãããã¼ãã«bãä½ã£ã¦2ã¬ã³ã¼ããINSERTãã¦ã¿ã¾ããã
mysql> CREATE TABLE b (f1 FLOAT, f2 FLOAT); Query OK, 0 rows affected (0.04 sec) mysql> INSERT INTO b VALUES(0.9,0.8999996); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO b VALUES(0.9,0.89999996); Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM b; +------+------+ | f1 | f2 | +------+------+ | 0.9 | 0.9 | | 0.9 | 0.9 | +------+------+ 2 rows in set (0.00 sec)
0.9ããã³0.9ã«è¿ãããªæ°2種é¡ãINSERTãã¦ã¿ãã¨ãããå
¨ã¦0.9ã¨ãã¦è¡¨ç¤ºããã¾ããã
mysql> SELECT * FROM b WHERE f1=f2; +------+------+ | f1 | f2 | +------+------+ | 0.9 | 0.9 | +------+------+ 1 row in set (0.00 sec) mysql> SELECT f1+0,f2+0 FROM b; +--------------------+--------------------+ | f1+0 | f2+0 | +--------------------+--------------------+ | 0.8999999761581421 | 0.8999996185302734 | | 0.8999999761581421 | 0.8999999761581421 | +--------------------+--------------------+ 2 rows in set (0.00 sec)
ã¨ããããf1ã¨f2ãçããã¬ã³ã¼ããSELECTãã¦ã¿ãã¨1ã¬ã³ã¼ãããããããã¾ãããã0.89999996ãã¨ã0.9ãã¨ã¯FLOATåã¨ãã¦åãå¤ã¨ãã¦æ ¼ç´ãããã®ã§ãããã0.8999996ãã¯ç°ãªãå¤ã¨ãã¦è§£éããããã¨ãåå ã§ãã
ããããæ¯è¼ããã¨ãã¯ç°ãªãå¤ã§ããã«ãé¢ãããSELECT * FROM b
ããã¨ãã®è¡¨ç¤ºãåããªã®ã¯åé¡ã§ããFLOATåã®å¤ãSELECTã§åãåºããåãåºããå¤ãUPDATEæã§å代å
¥ããå ´åã«å
ã®å¤ã¨å¤ãã£ã¦ãã¾ããã¨ã«ãªãã¾ããããæ··ä¹±ã®åå ã«ãªãããã¾ããã
ããã¯MySQLã½ã¼ã¹ã³ã¼ãstrings/dtoa.cä¸ã®my_gcvt
é¢æ°ã®ãã°ã ã¨æããã¾ããFLOATåã®å¤ã表示ããéãmy_gcvt
é¢æ°ã®å
é¨ã§è¡¨ç¤ºç²¾åº¦ã決å®ããå¦çãããã®ã§ãããFLOATåã®å ´åã¯FLT_DIG
æ¡ã¨ãªãã¾ãã
res= dtoa(x, 4, type == MY_GCVT_ARG_DOUBLE ? width : MY_MIN(width, FLT_DIG), &decpt, &sign, &end, buf, sizeof(buf));
ãã®FLT_DIG
ã¯ãCè¨èªã®floatåã§ç²¾åº¦ã失ããã«è¡¨ç¾ã§ãã10é²æ¡æ°ããæå³ããå®æ°ã§ãé常6ã¨ãªãã¾ãããããããã®æ¡æ°ã§ã¯FLOATåã¨ãã¦ç°ãªãæ°ãåã表è¨ã«ãã¦ãã¾ããé©åã¨ã¯æãã¾ãããæ¬æ¥çã«ã¯FLT_DIG+2
ã¨ãã¹ãã§ãããããã°FLOATã¨ãã¦ç°ãªãå¤ã10é²ã§ãç°ãªã表è¨ã§è¡¨ç¤ºã§ããã¯ãã§ãã
ãããæ¬å½ã«ãã°ãªã®ãä»æ§ãªã®ãã¯ãããã¾ããããæ··ä¹±ã®å ã§ããã®ã¯ééããªãã¨ããã§ãããã
ã¾ãããã®åé¡ãä»ã¾ã§ä¿®æ£ããã¦ããªããã¨èªä½ãFLOATåã®å©ç¨ãªã¹ã¯ã ã¨è¨ããããããã¾ãããå©ç¨è ã®å¤ãã§å質ãæ ä¿ã§ãããã¨ãæåOSSã®å¼·ã¿ã§ããã¯ãã§ãããéã«è¨ãã¨ãã¾ã使ããã¦ããªãæ©è½ã»ã©ãã°ã¯æ®ã£ã¦ãã¾ãããã§ããFLOATåã®æ¡ç¨ãæ¤è¨ããå ´åãä»ã®äººãã©ãã»ã©FLOATåãæ¡ç¨ãã¦ããã®ãï¼ã¨ãã観ç¹ãéè¦ãã¨æãã¾ãã
ã¡ãªã¿ã«ããã®ãããªåé¡ã¯DOUBLEåã§ã¯çºçãã¾ãããDOUBLEåã®å ´åã¯ãSELECTã§åãåºãã10é²è¡¨ç¾ã¨å
é¨çãªè¡¨ç¾ã¨ã1:1対å¿ãã¦ãããå
é¨çã«ç°ãªãå¤ã§ããã°å¿
ã10é²è¡¨ç¾ãç°ãªã£ã¦ãã¾ãã
ã¾ã¨ã
MySQLã®FLOATåã®æ§è³ªããã³åé¡ç¹ãææãã¾ããã
- FLOATåã§å°æ°ãæ±ãã¨ä¸¸ã誤差ãçºçãããããã®ãã¨ãç¥ããã«æ¡ç¨ããã®ã¯å±éº
- f+0ãªã©ã¨ããã¨DOUBLEåã¨ãã¦è©ä¾¡ããã誤差ãå«ãã å¤ã観測ã§ãã
- FLOATåã®å¤ã¯æé»çã«DOUBLEåã«ãã£ã¹ãããããã¨ããããå©ç¨è ããã£ã¹ãã®æåãç¥ããªãã¨æå¾ éãã®å¦çãè¡ããªããã¨ããã
- FLOATåãSELECTããçµæã¨å
é¨è¡¨ç¾ã¨ã¯1:1対å¿ãã¦ããªãããããã¯ãã°ã ã¨èãããã
- ããããFLOATåã®å©ç¨å®ç¸¾ãå°ãªãçãããããä»ã®åã»ã©ãã°ãåºãã£ã¦ããªãå¯è½æ§ãããã®ã§ã¯ãªãã
å¯ä¸FLOATåãæ¡ç¨ããã¡ãªããã¨ãã¦ãµã¤ãºãå°ãããã¨ãæãããã¾ããã大æµã®ç¶æ³ã§ã¯ä¸è¨ã®åé¡ã«ãããã¡ãªããã®æ¹ã大ããã®ã§ã¯ãªãã§ããããã
ä»åææããåé¡ãåé¿ããããã«ä¸è¨ã®ãããªæ¡ãèãããã¾ãã
- DECIMALåã使ã
- ä¸ããããå°æ°ãå é¨çã«ã¯1000åçã§æ±ããªã©ãã¦ãMySQLä¸ã§ã¯æ´æ°ã¨ãã¦æ ¼ç´ãã
- ä¸ãããã10é²è¡¨ç¾ã®å°æ°ãæååã¨ãã¦æ ¼ç´ãã
ã©ããæé©ãã¯ç¶æ³æ¬¡ç¬¬ã ã¨æãã¾ãããç§å人ã¯2çªç®ã®æ¡ã好ã¿ã§ããã¾ããæµ®åå°æ°ç¹æ°ã«åå詳ããå ´åã¯DOUBLEåãæ¡ç¨ãã¦ãããã§ãããã