PHPã®roundé¢æ°ã¨ã¯ä¸ä½ãªãã ã£ãã®ã
ï¼7/3 14:05追è¨ï¼Javaã«é¢ããè¨è¿°ã«ã¤ãã¦èª¤èªããã£ãã®ã§ç大ã«æ¸ãæãã¾ãããJava 6ãJava 7ãJava 8ããããã§å®è£ ãå¤ãã£ã¦ããããã§ãã
ï¼7/13 23:55追è¨ï¼æ¬è¨äºä¸ã§ã¯roundãåæ¨äºå ¥ã¨è¨ãåã£ã¦ãã¾ã£ã¦ãã¾ããããã¯çè ãC99ã®roundãåºæºã«èãã¦ããããã§ãããè¨èªã«ãã£ã¦ã¯å¶æ°ä¸¸ãã«ãªã£ã¦ããroundé¢æ°ãçããããã¾ãããã注æãã ããã
PHPã®roundé¢æ°ã«ã¤ãã¦ããããä¸ã§æ¬¡ã®ãããªè¨è¿°ãè¦ã¤ãã¾ããã
åæ¨äºå ¥ã®è¨ç®ãééããå¯ä¸ã®è¨èªã¨ãã¦çãããã¦ãã¾ãããããã®ãã°ã¯æ²»ã£ã¦ããããããã¾ããï¼æ²»ã£ã¦ãªãããããã¾ããï¼
åè¨èªãé¢ç½ããããç´¹ä»ããå 容ã¨ã¯ãããããã¶ãéãªç解ã ãªã¼ã¨ããå°è±¡ã§ãããããµããªè©±ã ãã§PHPãdisããç¶ããã®ãã©ããã¨æãã®ã§ãä¸é£ã®roundé¢æ°ã®è©±é¡ã«ã¤ãã¦åãªãã®ç·æ¬ããã¦ã¿ããã¨æãã¾ãã
以ä¸ããããªããããã§ç´¹ä»ãã¦ããã¾ãã
- PHP以å¤ã§ãåæ¨äºå ¥é¢æ°ã®ãã°ã£ã½ãæåã¯çãããªã
- PHPã®ç¾å¨ã®å®è£
ã¯æ´æ°ã¸ã®ä¸¸ãã«ã¤ãã¦ã¯ä»ã®è¨èªã¨åã
- å½æ話é¡ã«ãªã£ãroundé¢æ°ã®å®è£ ã¯2009å¹´ãªãªã¼ã¹ã®PHP 5.3.0ã§ãªãã¬ã¼ã¹æ¸
çµç·¯ãªã©
å ãã¿ãç¥ããªã人åãã«çµç·¯ãç´¹ä»ãã¾ãã
åã2007å¹´ã«PHPã½ã¼ã¹ã³ã¼ãä¸ã®åæ¨äºå ¥é¢æ°ã®å®è£ ã«æ°æã¡æªããã¸ãã¯ãã³ãã¼ãè¦ã¤ãã¦ãPHPの奇妙なround関数ãã¨ããè¨äºã«ããã¨ããããªããRubyã®ã¾ã¤ãã¨ããã®æ¥è¨ã«æ¾ããã¦ããºã£ãã¨ããäºä»¶ãããã¾ããã
åé¡ã«ãªã£ãroundé¢æ°ã®å®è£ ã¯çç´ã«è¨ã£ã¦ãã£ã¤ãæããµãããã®ã§ãdisããã¦ãä»æ¹ãªãå 容ã ã£ãã¨æãã¾ããããããåèªèº«ããPHPæ°æã¡æªããããã²ã©ããããã¨ããã¤ããã§è¨äºãæ¸ããããã§ããããããéPHPã¦ã¼ã¶ã¼ãå®å ¨å°å¸¯ããPHPãå©ãããã ãã«ä¹ã£ãã£ã¦ããã®ã«è¥å¹²ã¤ã©ã£ã¨ããã®ã§ãããåããå®å ¨å°å¸¯ã ã¨æã£ã¦ãåå°ãå®ã¯èããã ããã¨è¨ããããããã«ä»è¨èªã®æµ®åå°æ°ç¹æ°å¨ãã®ãã°ãæ¢ãã¦ã¿ã¾ããã
ãããã¦èª¿ã¹ã¦ããä¸ã§ãæµ®åå°æ°ç¹æ°ã®åæ¨äºå ¥ã«ã¤ãã¦ä½åãã¨ãã¸ã±ã¼ã¹ããããã¨ã«æ°ã¥ãã¾ãããã¾ããå種ããã°ã©ãã³ã°è¨èªã®ä¸ã®äººãå¿ ãããæµ®åå°æ°ç¹æ°ã«è©³ãããªããã¨ãããã£ã¦ãã¾ãã*1ãã¾ãã¯roundé¢æ°ã®ã¨ãã¸ã±ã¼ã¹ã¨åè¨èªã®å¯¾å¿ç¶æ³ã«ã¤ãã¦ç´¹ä»ãã¾ãã
åæ¨äºå ¥ã®ã¨ãã¸ã±ã¼ã¹1ï¼0.49999999999999994
0.5ããå°ããå精度浮åå°æ°ç¹æ°ã®ä¸ã§æ大ã®æ°ã0.49999999999999994ã§ãããããåæ¨äºå ¥ããã¨ããªããç¹°ãä¸ãã£ã¦1ã«ãªã£ã¦ãã¾ãå®è£ ãããã¾ãã
ä¸è¨è¨äºã§ç´¹ä»ããæç¹ã§ã¯ãRubyã¨Pythonããã®ãããªå®è£ ã«ãªã£ã¦ãã¾ãããããã¯åæ¨äºå ¥ããå¼æ°ãæ£ãªã0.5足ãã¦å°æ°ç¹ä»¥ä¸ãåãæ¨ã¦ããã¨ããå®è£ ã«ãªã£ã¦ããå ´åã«çºçãã¾ãããã®åé¡ãåé¿ããå®è£ ã¯ãå¼æ°ãæ£ã®ã¨ãå°æ°ç¹ä»¥ä¸ãåãæ¨ã¦ã¦å ã®æ°ã¨ã®å·®ã0.5以ä¸ãªã1.0ã足ããã§ããããã¼æµ®åå°æ°ç¹æ°ã£ã¦é£ããã§ããã
åæ¨äºå ¥ã®æåãããã¥ã¢ã«éãã¨ã¯è¨ããªãå¦çç³»ãPHP以å¤ã«ããã£ããã¨ããã®ã¯ãã®ä¾ã ãè¦ã¦ãæããã§ãããã
ã¡ãªã¿ã«ãæ¬ä»¶ã¯Rubyã»Pythonã¨ãææ°çã§ã¯ä¿®æ£æ¸ã¿ã¨ãªãã¾ãï¼ããªãåããä¿®æ£ããã¦ããã¯ãã§ãã詳細ãªææã¯ææ¡ãã¦ãã¾ããï¼ã
åæ¨äºå ¥ã®ã¨ãã¸ã±ã¼ã¹2ï¼9007199254740991.0
9007199254740991.0ãåæ¨äºå ¥ããã¨ãªããç¹°ãä¸ãã£ã¦9007199254740992.0ã«ãªã£ã¦ãã¾ãå®è£ ãããã¾ãããã®æ°ã¯å精度浮åå°æ°ç¹æ°ã®ä»®æ°é¨å ¨bitã1ã§ãããããªæ°ã«ãªãã¾ãã詳細ã¯ä¸è¨ã®è¨äºãã覧ãã ããã
ãããå ã»ã©ã®0.49999999999999994ã¨åããããå¼æ°ãæ£ãªã0.5足ãã¦å°æ°ç¹ä»¥ä¸ãåãæ¨ã¦ããã¨ããå®è£ ã®ã¨ãã«åé¡ã«ãªãä¾ã§ããä¸è¨è¨äºã®ã¿ã¤ãã³ã°ã§ã¯Pythonã ãã該å½ãã¾ãããããã®ç´åãããã¾ã§ã¯Rubyãåæ§ã®å®è£ ã§ããã
ãã¡ãããç¾å¨ã§ã¯Pythonã®å®è£ ãä¿®æ£ããã¦ãã¾ãã
Javaã®åæ¨äºå ¥ã«ã¯ãã°ãªã®ãä»æ§ãªã®ãå¾®å¦ãªã¨ãã¸ã±ã¼ã¹ãJava 7ã¾ã§åå¨ãã¦ãã
ãã¦ãä¸è¨2ã¤ã®ã¨ãã¸ã±ã¼ã¹ã«ã¤ãã¦ã§ãããJava 6ã®roundé¢æ°ã¯2ã¤ã¨ãééãã£ã½ãæ¹ã«ä¸¸ãã¾ãã
public class RoundTest { public static void main(String[] args) { double d1 = 0.49999999999999994d; double d2 = 9007199254740991.0d; System.out.println("d1: " + d1); // 0.49999999999999994 System.out.println("round(d1): " + Math.round(d1)); // Java 6: 1, Java7-8: 0 System.out.println("d2: " + d2); // 9.007199254740991E15 System.out.println("round(d2): " + Math.round(d2)); // Java 6-7: 9007199254740992, Java8: 9007199254740991 } }
ããããJava6ã®æåã¯ãã°ã¨ãè¨ãåãã¾ãããJava 6ã®ããã¥ã¢ã«ã«ã¯ä¸è¨ã®ãããªè¨è¿°ãããã¾ãã
public static long round(double a)
Returns the closest long to the argument. The result is rounded to an integer by adding 1/2, taking the floor of the result, and casting the result to type long. In other words, the result is equal to the value of the expression:
(long)Math.floor(a + 0.5d)
http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html#round%28double%29
å ã»ã©ããã¤ãã¤ããªå®è£ ã¨ãã¦ç´¹ä»ãã¦ããã0.5足ãã¦å°æ°ç¹ä»¥ä¸ãåãæ¨ã¦ãããå é¨å®è£ ã ã¨æ¸ãã¦ããã¾ãã®ã§ãä¸ã®æåã¯ä»æ§ãªã®ããããã¾ããããã®è¨è¿°ã ãã§ã¨ãã¸ã±ã¼ã¹ã®åããJavaããã°ã©ããã©ãã»ã©ãããã¯çåã§ãããææ¸åããã¦ãããã¨èªä½ã¯ç´ æ´ãããã¨åã¯å½æãã絶è³ãã¦ãã¾ããã
ã¨ããã§ãJava 7以éã®ããã¥ã¢ã«ããã¯この内部実装に関する記述が消えているããã§ãããã©ãã¯ããã¯é ããè¨äºãJavaのMath.roundがバグっていないと言える可能性について - What will be done tomorrow?ãã«ããã°ãJava 7ã§å®è£ ãå¤ãã£ãã¿ã¤ãã³ã°ã§ããã¥ã¢ã«ã®è¨è¿°ãå¤ãã£ãã¨ãããã¨ã®ããã§ãããã ããã®ã¿ã¤ãã³ã°ã§ã¯d1ã®ã¿æ£ãã丸ããããã«ãªã£ãããã§ãd2ã¯ç¹°ãä¸ãã£ã¦ãã¾ãå®è£ ã ã£ãããã§ããããã¯ããã¥ã¢ã«ã®è¨è¿°ãthe value of the argument rounded to the nearest long valueãã«åãã¦ããã¨è¨ããã§ãããã
Java 8ã§ããã«å®è£ ãå¤ãã£ãããã§ãJava 8ããã¯ã¨ãã¸ã±ã¼ã¹2件ã¨ãæ£ããæ¹åã«ä¸¸ããããã«ãªã£ã¦ãã¾ãã
æ¬ä»¶ãOSãCPUã«ãä¾åããã¨èããããã®ã§ç°å¢ã«ãã£ã¦åç¾ã§ãããã§ããªãã£ããããã¨æãã¾ãããMacOSXç°å¢ã®Oracle JDKã§ã®å®é¨çµæãæ·»ä»ãã¦ããã¾ãã
åæ¨äºå ¥ã§å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããä»æ§ãããããé£ãã
è¯ãé¢æ°ã®æ¡ä»¶ã®ä¸ã¤ã«ãæåãç´æçã§ãããã¨ãããã¨ãããããã«æãã¾ããç¹ã«è¨èªã®æ¨æºé¢æ°ã§ããã°ãé·ã 説æããªãã¨ä½¿ããªããããªé¢æ°ã¯å®³ã®æ¹ãå¤ããããã ã¨è¨ããã§ãããã
ãã®æå³ã§ãroundé¢æ°ã§å°æ°ç¹ä»¥ä¸(n+1)ä½ãåæ¨äºå ¥ãã¦å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããå®è£ ã¯å±éºã§ããn=0ã®ã¨ããã¤ã¾ãæ®éã®æ´æ°ã¸ã®ä¸¸ãã«ã¤ãã¦è¨ãã°2é²ã®æµ®åå°æ°ç¹æ°ã§ã0.5ã1.5ãªã©ã誤差ç¡ã表ç¾ã§ããã®ã§åé¡ã¨ã¯ãªãã¾ããããn>0ã®å ´åã«ã¤ãã¦è¨ãã°åæ¨äºå ¥ã®å¢çç·ï¼0.05ã0.005ï¼ã丸ã¾ã£ãå¾ã®æ°ï¼0.1ã0.01ï¼ãããã¿ãªè¡¨ç¾ã§ããªããããä»æ§ãè¨èªåãããã¨èªä½ãé£ããã¨è¨ãã¾ãã
容æã«æãã¤ãå®è£ ã¨ãã¦ã10^nåãã¦æ´æ°ã¸ã®ä¸¸ããè¡ã£ã¦10^nã§å²ãã¨ãããã®ãããã¾ããããããæµ®åå°æ°ç¹æ°ãä¸ç¨æã«10^nåããã®ã¯èª¤å·®ã®èç©ãçã¿ãããå¦çã§ããå®éã次ã®ä¾ã§ã¯Rubyã¨Pythonãç´æã«åããçµæãè¿ãã¦ãã¾ãã¾ãã
$ ruby -e 'x=5.015; print x.round(2), "\n";' 5.01 $ python -c 'x=5.015; print round(x, 2),"\n";' 5.01
ããããå®è£ ã«å¯¾ããåé¡ç¹ã®ææã3å¹´ã»ã©åã«è¨äºã«ãã¾ããã
ãã®å¾ãããè¯ãå®è£ ã¯ã©ã®ãããªãã®ãï¼ã¨ããè°è«ã«çºå±ãã¦shiroããã®ç´ æ´ãããè¦è§£ãèªããã¨ãåºæ¥ãã®ã¯è¯ãã£ãã¨æã£ã¦ãã¾ãã
詳細ã¯è¨äºãèªãã§é ãã¨ãã¦ããã¯ãã2é²ã®æµ®åå°æ°ç¹æ°ã10é²è¡¨è¨ã§å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããé¢æ°ã®ç´æçãªä»æ§ã¯åå¨ããªããã¨ããã®ãçµè«ããªã¨æãã¾ãã
å ã ã®PHPã®roundé¢æ°ããå°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããæåãç´æçã«ãããã¨ãã¦å¤±æãã¦ãã¾ã£ããã®ã§ãããã®ä»¶ããæã ãå¦ã¶ã¹ããã¨ã¯æ¡ç¨ãããå®è£ ã®ã¾ããã«ã¤ãã¦ã§ã¯ãªããå°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããä»æ§ãæ¡ç¨ããã¨ããä»æ§çå®æ®µéã®å¤±æã«ã¤ãã¦ã§ã¯ãªãã§ããããã
ä½è«ï¼ãã®å¾Rubyã¯å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããä»æ§ãæ¡ç¨ãã
ã¨ããã§ãPHPã®roundé¢æ°ã«é¢ããè°è«ããã¦ãã2007å¹´å½æææ°ã ã£ãRuby 1.8ç³»ã®roundé¢æ°ã«ã¯å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããæå®ã¯ããã¾ããã§ãããã¤ã¾ããPHPã®ãããªæ©ã¿ã¯ç¡ãã£ããã¨ã«ãªãã¾ããåã¨ãã¦ã¯ããã®å¹³åãªç¶æ ãç¶æãã¦é ãããã¨æã£ã¦ãã¾ããã
ãã®å¾ã2008å¹´é ã«ã¾ã¤ãã¨ããã¨é£²ã¿ä¼ã§åå¸ããã¦é ãæ©ä¼ãããããRubyã®roundé¢æ°ã«ã¯å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããä»æ§ã¯çµ¶å¯¾ã«å ¥ããªãæ¹ãããã§ãããçãªé²è¨ãããããã«è¨æ¶ãã¦ãã¾ããåå¾ã®æèãä½ããªããä¼ãããã®ã§ãã§ãã³ã¨ããã¦ãããããªæ°ããã¾ãããåã¨ãã¦ããããªãã¢ãä»æ§ãæ¡ç¨ããã¡ããè¨èªã¯PHPãããã ããã¨æã£ã¦ããã®ã§ã詳細ã®è©±ããããã¨ãããã¾ããã§ããã
ã¨ãããããã®å¾Ruby 1.9ç³»ã®roundé¢æ°ã«å°æ°ç¹ä»¥ä¸nä½ã§ä¸¸ããä»æ§ãå ¥ã£ã¦ãããã¨ã«ãªãã¾ããåã¯çµç·¯ã追ã£ã¦ãã¾ããããã¦ã¼ã¶ã¼ã®å£°ã«æããªãã£ããã§ãããããããã¾ã§èª°ãä¸æºãªã使ã£ã¦ãããããªããããã§ããã©ã
ç¾å¨ã®PHPã®roundé¢æ°ã®å®è£
ç¾å¨ã®PHPã®roundé¢æ°ã®å¦çã¯ãåé¡ã®ãã£ãå®è£ ãPHP 5.3.0ã§æ¹åããã¦ããå¤ãã£ã¦ãã¾ããã詳細ã¯æ¬¡ã®è¨äºã§ç´¹ä»ãã¦ãã¾ãã
ãã®é ããPHPã®ä»æ§å¤æ´ã«é¢ããè°è«ã¯RFCã¨å¼ã°ããWikiææ¸ãã¼ã¹ã§è¡ãããããã«ãªãã大ããå¤æ´ã¯å¤ãã®äººã®ç®ãå ¥ãããã«ãªãã¾ãããã¾ããä»æ§ããã£ã¡ãããã¥ã¡ã³ãã¨ãã¦æ®ãããã«ãªã£ãã®ã大ããªå©ç¹ã§ãããã®ä¸¸ãå¦çãä¸è¨ã®RFCãã¼ã¹ã§è°è«ããã¦ããããããèªãã°èª°ã§ãä»æ§ææ¡ã§ããç¶æ ã«ãªã£ã¦ãã¾ãã
- ãPHP: rfc:roundingã
ã¡ãªã¿ã«ãæ°ããªä¸¸ãå¦çã§ã¯æ´æ°ã¸ã®ä¸¸ãã¯ä»ã®è¨èªã¨å®å ¨ã«åãã§ã±ãã®ä»ãæã¯ããã¾ããã
ä¸æ¹ãå°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããå¦çã¯ç´æçã¨ã¯è¨ãã¾ããã丸ãä½ç½®ãå¤ããªãã2å丸ãããããªå¦çã«ãªã£ã¦ãããä¸é¨ã¨ãã¸ã±ã¼ã¹ã§ãã°ã£ã½ãæåããããããªãããæå³PHPãããå¦çã«ãªã£ã¦ãã¾ãã
ã¨ã¯ãããå ã»ã©ããç¹°ãè¿ãã¦ããããã«å°æ°ç¹ä»¥ä¸nä½ã«ä¸¸ããä»æ§ãæ¡ç¨ããæç¹ã§å¤±æã ã¨ããã®ãå人çè¦è§£ã§ããæ¢ã«ç´¹ä»ããéãä»ã®è¨èªã誤差ä¸çã§å®è£ ãã¦ããããã§ãPHPã ããå¤ã¨ããã®ãéãæ°ããã¾ãã
ãããªããã§ãPHP 5.3.0以éã®roundé¢æ°ã¯ä»ã®è¨èªã¨åçã¨è¨ã£ã¦ãã¾ã£ã¦å·®ãæ¯ããªãã§ãããã
ã¡ãªã¿ã«å½æ話é¡ã«ãªã£ãroundé¢æ°ãå®è£ ããã¦ããã®ã¯PHP 5.2ç³»ã§ããã2009å¹´ã«5.3ç³»ããªãªã¼ã¹ããã¦ãªãã¬ã¼ã¹ãã¯ãã¾ãã2011å¹´ã«ã¯5.2ç³»ã®ã»ãã¥ãªãã£ãµãã¼ããåãã¦ããç¶æ³ã§ããå®å ¨ã«æ話ã¨ããæãã§ããã
ãããã«
åæ¨äºå ¥ããã誰ã§ãå®è£ ã§ããã£ã¦æãã§ããï¼æå¤ã¨ããã§ããªãããã§ããããã³ãã«ã
*1:ãã¡ããå¹³åçã«ã¯è©³ãã人ãå¤ãã§ãããã¹ã¼ãã¼è©³ãã人ããããããã¾ã