為什么在Java 6上Math.round(0.499999999999999917)舍入為1

總覽

錯誤表示錯誤和算術舍入錯誤有兩種類型,它們在浮點計算中很常見。 在此簡單示例中,這兩個錯誤組合在一起,在Java 6中Math.round(0.4999999999999999999917)舍入為1。

表示錯誤

浮點數是以2為底的格式,表示所有數字都表示為2的冪的和。例如6.25是2 ^ 2 + 2 ^ 1 + 2 ^ -2。 但是,即使像0.1這樣的簡單數字也無法準確表示。 轉換為BigDecimal時,這一點變得很明顯,因為它將保留實際表示的值而無需取整。

new BigDecimal(0.1)= 0.1000000000000000055511151231257827021181583404541015625
BigDecimal.valueOf(0.1)= 0.1

使用構造函數獲取實際表示的值,使用valueOf給出與打印 精度字相同的舍入值

解析數字時,會將其舍入為最接近的表示值。 這意味著存在一個略小于0.5的數字,由于它是最接近的表示值,因此將四舍五入為0.5。

下面用蠻力搜索舍入為1.0的最小值

public static final BigDecimal TWO = BigDecimal.valueOf(2);public static void main(String... args) {int digits = 80;BigDecimal low = BigDecimal.ZERO;BigDecimal high = BigDecimal.ONE;for (int i = 0; i <= 10 * digits / 3; i++) {BigDecimal mid = low.add(high).divide(TWO, digits, RoundingMode.HALF_UP);if (mid.equals(low) || mid.equals(high))break;if (Math.round(Double.parseDouble(mid.toString())) > 0)high = mid;elselow = mid;}System.out.println("Math.round(" + low + ") is " + Math.round(Double.parseDouble(low.toString())));System.out.println("Math.round(" + high + ") is " + Math.round(Double.parseDouble(high.toString())));
}

源代碼

在Java 7上,您得到以下結果。

Math.round(0.49999999999999997224442438437108648940920829772949218749999999999999999999999999) is 0
Math.round(0.49999999999999997224442438437108648940920829772949218750000000000000000000000000) is 1

令人驚訝的是,在Java 6中,您獲得了關注。

Math.round(0.49999999999999991673327315311325946822762489318847656250000000000000000000000000) is 0
Math.round(0.49999999999999991673327315311325946822762489318847656250000000000000000000000001) is 1

這些數字從何而來?

Java 7值是0.5和前一個表示值之間的中點。 高于此中點時,解析時該值將舍入為0.5。

Java 6值是0.5之前的值與其之前的值之間的中點。

Value 0.5 is 0.5
The previous value is 0.499999999999999944488848768742172978818416595458984375
... and the previous is 0.49999999999999988897769753748434595763683319091796875The mid point between 0.5and 0.499999999999999944488848768742172978818416595458984375is 0.4999999999999999722444243843710864894092082977294921875... and the mid point between 0.499999999999999944488848768742172978818416595458984375and 0.49999999999999988897769753748434595763683319091796875is 0.4999999999999999167332731531132594682276248931884765625

為什么Java 6的值更小

在Java 6 Javadoc中, Math.round(double)被定義為

(long)Math.floor(a + 0.5d)

此定義的問題在于0.49999999999999994 + 0.5的舍入誤差為1.0。

在Java 7 Javadoc Math.round(double)中,它僅聲明:

返回最接近參數的長整數,并舍入四舍五入。

那么Java 7如何解決這個問題?

Java 7的Math.round的源代碼如下所示

public static long round(double a) {if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5return (long)floor(a + 0.5d);elsereturn 0;
}

最大值小于0.5的結果將進行硬編碼。

那么0x1.fffffffffffffp-2是什么呢?

它是浮點值的十六進制表示。 它很少使用,但是它很精確,因為所有值都可以無錯誤地表示(最多53位)。

相關鏈接

錯誤ID:6430675 Math.round對于0x1.fffffffffffffpp-2具有令人驚訝的行為
為什么Math.round(0.49999999999999994)返回1

參考: 為什么在Java 6上 ,我們的JCG合作伙伴 Peter Lawrey在Vanilla Java博客上將Math.round(0.499999999999999917)舍入為1 。


翻譯自: https://www.javacodegeeks.com/2012/04/why-mathround0499999999999999917-rounds.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/373137.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/373137.shtml
英文地址,請注明出處:http://en.pswp.cn/news/373137.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

單利模式

class Singleton{ public:static Singleton* GetInstance(){if (m_pInstance nullptr){m_pInstance new Singleton;}return m_pInstance;} private:Singleton(){}//需要將構造和析構定義成私有的防止外界構造和析構~Singleton(){}static Singleton* m_pInstance;//static所有…

C語言switch中break的作用,C語言中switch...case語句中break的重要性

在C語言中switch...case語句是經常用到的&#xff0c;下面我介紹一下在使用該語句時候需要注意的一個細節問題。話不多說&#xff0c;直接舉例子&#xff1a;例子1&#xff1a;switch(fruit){case 1:printf("apple"); break;case 2:printf("banana"); brea…

BZOJ 1898: [Zjoi2005]Swamp 沼澤鱷魚 [矩陣乘法]

1898: [Zjoi2005]Swamp 沼澤鱷魚 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1082 Solved: 602[Submit][Status][Discuss]Description 潘塔納爾沼澤地號稱世界上最大的一塊濕地&#xff0c;它地位于巴西中部馬托格羅索州的南部地區。每當雨季來臨&#xff0c;這里碧波蕩漾…

從Spring開始,Java EE 6必須具備哪些附加功能?

我是一名高級Java開發人員&#xff0c;必須研究應用程序架構師選擇的技術。 我最多只能表達對特定技術的看法&#xff0c;不能做出/影響技術選擇的決定。 因此&#xff0c;在我的正式項目中&#xff0c;我別無選擇從Spring遷移到JavaEE6或從JavaEE6遷移到Spring。 我堅信&#…

UML類圖與類的關系詳解

在畫類圖的時候&#xff0c;理清類和類之間的關系是重點。類的關系有泛化(Generalization)、實現&#xff08;Realization&#xff09;、依賴(Dependency)和關聯(Association)。其中關聯又分為一般關聯關系和聚合關系(Aggregation)&#xff0c;合成關系(Composition)。下面我們…

教程:Hibernate,JPA和Spring MVC –第2部分

本教程將向您展示如何使用基本的Hibernate / JPA應用程序&#xff0c;如何將其轉換為Spring MVC Web項目&#xff0c;以便能夠在Web瀏覽器中查看數據庫&#xff0c;以及最后使用Spring的Transactional注釋來減少樣板代碼。 本教程假定您熟悉Java和Maven&#xff0c;并且已經完成…

算法轉換c語言程序,(轉)C語言實現卡爾曼濾波算法程序

非常感謝原作者&#xff0c;我在這個的基礎上轉換成純整形運算。STM32F103 12位ADC先放大1000倍再運算&#xff0c;理論上可以保留小數點后三位的結果。效果非常不錯&#xff0c;運算速度也快&#xff0c;72M時鐘 1-2uS左右(根據MDK周期數)。]uint32_t KalmanFilter(int32_t Re…

Java 8的烹調方式–拼圖項目

什么是Project Jigsaw&#xff1a;Project Jigsaw是使Java編譯器模塊知道的項目。 多年以來&#xff0c;Java API一直是整體的&#xff0c;即從代碼的任何部分都可以平等地看到整個API。 還沒有任何方法可以聲明代碼對任何其他用戶庫的依賴關系。 拼圖項目試圖以非常有效的方式…

python之路-SQLAlchemy

SQLAchemy SQLAlchemy是Python編程語言下的一款ORM框架&#xff0c;該框架建立在數據庫API之上&#xff0c;使用關系對象映射進行數據庫操作&#xff0c;簡言之便是&#xff1a;將對象轉換成SQL&#xff0c;然后使用數據API執行SQL并獲取執行結果。 安裝&#xff1a; pip3 inst…

POJ 1751 Highways

題意&#xff1a;n個城市&#xff0c;然后把n個城市的坐標都給你&#xff0c;然后給你m條已經修好的道路&#xff0c;然后給出m個已經修好道路的城市a&#xff0c;b&#xff0c; However, they want to guarantee that every town is highway-reachable from every other town.…

C語言編程中void什么意思,程序設計中遇到的void到底是什么意思

部分編程的初學者都會問"void是什么意思","為什么很多函數前都要加個void".實際上,void最簡單的解釋就是把0轉換成空類型的意思。下面用各個開發語言來詳解void1.C語言中的void表示空類型&#xff0c;它跟int&#xff0c;float是同地位的&#xff0c;一般用…

Linux中vim編輯器的縮進的功能鍵

vim編程時,經常需要對代碼進行縮進處理,以增加程序的可讀性和后期的代碼維護. 可以采用多種方式達到縮進的目的: 1) 命令模式(command mode) 2) Visual模式&#xff08;visual mode&#xff09; 2) 輸入模式(entry mode) 3) 末行模式(last-line mode) 4) 在/etc/vimrc有給予vim…

JSF 2,PrimeFaces 3,Spring 3和Hibernate 4集成項目

本文展示了如何集成JSF2&#xff0c;PrimeFaces3&#xff0c;Spring3和Hibernate4技術。 它為Java開發人員提供了一個通用的項目模板。 另外&#xff0c;如果Spring不用于業務和數據訪問層&#xff0c;則可以提供JSF – PrimeFaces和Hibernate集成項目。 二手技術&#xff1a…

c語言編程文件中刪除數據結構,C語言數據結構實戰(一)順序表的插入與刪除

今天學習了思成老師的數據結構實戰教程 寫了一個順序表 插入和刪除的操作 把源碼共享給大家 一共包括list.c stu.h main.c list.h .h文件是頭文件 需要引入 具體的功能我都已經在代碼中寫明了list.h代碼如下&#xff1a;//線性表的定義在頭文件中實現#ifndef _LIST_H#define …

內存使用分析工具Valgrind簡單用法

轉載自 http://www.cnblogs.com/sunyubo/archive/2010/05/05/2282170.html 暫時還未使用過&#xff0c;記錄下&#xff0c;記錄下&#xff0c;記錄下 Valgrind的主要作者Julian Seward剛獲得了今年的Google-OReilly開源大獎之一──Best Tool Maker。讓我們一起來看一下他的作品…

Lucene概述第一部分:創建索引

介紹 我最近一直在與開源搜索引擎Lucene合作 。 我不是專家&#xff0c;但是由于我只是瀏覽了一些相當稀疏的文檔并將應用程序從Lucene的很舊的版本遷移到了最新版本的2.4&#xff0c;所以我在總體上很清楚。 Lucene的文檔有點讓人難以想象&#xff0c;因此我想趁此機會在我腦海…

初識openstack

一、 什么是openstack&#xff1f; OpenStack是一個由NASA&#xff08;美國國家航空航天局&#xff09;和Rackspace合作研發并發起的&#xff0c;以Apache許可證授權的自由軟件和開放源代碼項目。 二、openstack前世今身 openstack是一個跟Eucalyptus,AWS(Amazon web Service)類…

c語言case多語句的取值,Switch Case語句中多個值匹配同一個代碼塊的寫法

C&num;&plus;JQuery&plus;&period;Ashx&plus;百度Echarts實現全國省市地圖和餅狀圖動態數據圖形報表的統計在目前的一個項目中,需要用到報表表現數據,這些數據有多個維度,需要同時表現出來,同時可能會有大量數據呈現的需求,經過幾輪挑選,最終選擇了百度的e…

php解決下單、抽獎并發導致的庫存負數的問題

我們知道數據庫處理sql是一條條處理的&#xff0c;假設購買商品的流程是這樣的&#xff1a; sql1:查詢商品庫存 if(庫存數量 > 0) { //生成訂單... sql2:庫存-1 } 當沒有并發時&#xff0c;上面的流程看起來是如此完美&#xff0c;假設同時兩個人下單&#xff0c;而…

在Spring中使用JDBCJobStore配置Quartz

我將開始一些有關Quartz Scheduler內部&#xff0c;提示和技巧的系列文章&#xff0c;這是第0章-如何配置持久性作業存儲。 在Quartz中&#xff0c;您基本上可以在將作業和觸發器存儲在內存中以及在關系數據庫中進行選擇&#xff08; Terracotta是最近添加的混合功能&#xff0…