java 0.05 0.01_关于数字:Java Double值= 0.01更改为0.009999999999999787

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:

Why not use Double or Float to represent currency?

我正在为我的高中课程编写一个Java的基本命令行程序。我们现在只处理变量。它用于计算购买后您的零钱中任何类型的纸币和硬币的数量。这是我的计划:

class Assign2c {

public static void main(String[] args) {

double cost = 10.990;

int paid = 20;

double change = paid - cost;

int five, toonie, loonies, quarter, dime, nickel, penny;

five = (int)(change / 5.0);

change -= five * 5.0;

toonie = (int)(change / 2.0);

change -= toonie * 2.0;

loonies = (int)change;

change -= loonies;

quarter = (int)(change / 0.25);

change -= quarter * 0.25;

dime = (int)(change / 0.1);

change -= dime * 0.1;

nickel = (int)(change / 0.05);

change -= nickel * 0.05;

penny = (int)(change * 100);

change -= penny * 0.01;

System.out.println("$5   :" + five);

System.out.println("$2   :" + toonie);

System.out.println("$1   :" + loonies);

System.out.println("$0.25:" + quarter);

System.out.println("$0.10:" + dime);

System.out.println("$0.05:" + nickel);

System.out.println("$0.01:" + penny);

}

}

这一切都应该有效,但在最后一步,当剩下0.01美元时,硬币的数量应该是1,而不是0。在进入代码并将更改值输出到控制台几分钟后,我发现在最后一步,当Change=0.01时,它变为0.0099999999787。为什么会这样?

不能用二进制正确表示所有的小数部分。使用整数执行这些操作,或者自己处理舍入。这个问题(或它的变体)在这里被问了数百次。这里有一个很好的参考:download.oracle.com/docs/cd/e19957-01/806-3568/…

只做mod:p比较容易。

aa然后我们又去了……

即使我从未使用bigdecimal(因为我发现msexcell有不同,但这只是我的问题),请阅读[来自otn的一个线程][1],[1]:forums.oracle.com/forums/…

用double表示货币是个坏主意,为什么不用double或float表示货币呢?.我建议使用BigDecimal或以美分计算。

用美分计算几乎总是比使用BigDecimalimo更好。

@马特球,有明显的不动点算术问题,即你要么失去准确性,不是整数,或需要另一个解决方案。因为中间计算的精确度只有1美分,这听起来像是灾难的前兆。

@VOO:对于用户正在做的应用程序来说,1分的准确度是非常好的。

@奥利·查尔斯沃思你是说一个没有实际用途的应用程序?;)当然可以,但了解可能解决方案的所有优点和缺点总是一个好主意(尤其是如果你这样做的唯一原因是学习新的东西)。如果准确度很重要的话,用美分计算当然不是"几乎总是比大小数更可取"的(而且根据你所做的计算,最终结果可能明显会相差1%以上)。我能看到的大小数的唯一缺点是性能

0.01在浮点值中没有精确的表示(对于这一点,0.1和0.2都没有)。

你可能应该用整数类型来做你所有的数学运算,代表硬币的数量。

真的。有种感觉,但我不知道。那我用美分来计算这个

+1好主意,但不总是适用于"bigdecimal"是不可能分解的方式。

doubles内部不是十进制的,而是二进制的。它们的存储格式相当于"100101乘以10000"(我正在简化,但这是基本思想)。不幸的是,这些二进制值的组合并不能精确到小数0.01,这就是其他答案所说的浮点数字不100%准确,或者0.01在浮点中没有精确的表示。

处理这个问题的方法有很多种,有些比其他更复杂。在您的情况下,最好的解决方案可能是在任何地方都使用int,并以美分为单位保留值。

正如其他人已经说过的,不要在财务计算中使用双数。

本文http://download.oracle.com/docs/cd/e19957-01/806-3568/ncg_goldberg.html(每个计算机科学家都应该知道浮点运算的内容)是理解计算机浮点运算的必读材料。

浮点数永远不会100%准确(不完全正确,请参阅下面的注释)。你不应该直接比较它们。也是整数舍入。做到这一点的最好方法可能是用美分计算,然后再转换成美元(1美元=100美分)。通过转换为整数,您将失去精度。

说"浮点数永远不会100%准确"是不对的。

我想我应该说你不能可靠地比较它们?

0.5是100%准确的。正如现在(或者可以是)2的大多数幂,以及2的大多数倍数(只要尾数可以容纳分数的分子)。当你得到分母不是2的幂的分数,或者分子太大不能完全表示的分数时,你就会遇到舍入误差。

啊,是的,你是对的。谢谢。

我相信你知道有些分数的十进制表示法终止了(例如0.01),而有些则没有终止(例如2/3=0.66666…)。问题是,分数的终止取决于你所处的基数;特别是,.01不以二进制结尾,所以即使double提供了很多精度,它也不能精确地表示.01。正如其他人所说,使用bigdecimal或定点整数计算(将所有内容转换为美分)可能是最适合使用货币的方法;要了解有关浮点的更多信息,可以从浮点指南开始——每个程序员都应该了解浮点算法。

这是一个多次出现的问题。底线是,在使用二进制浮点的计算机(Java需要的)上,只有分母是2的幂的分数可以精确地表示。

同样的问题以十进制出现。例如,1/3变成0.3333333…,因为3不是10的因子(我们用十进制表示的基数)。同样,1/17、1/19等。

在二进制浮点中,同样的基本问题出现了。主要的区别是,在十进制中,由于5是10的一个因子,1/5可以精确表示(1/5的倍数也是如此)。由于5不是2的因子,1/5不能用二进制浮点精确表示。

然而,与人们普遍认为的相反,有些分数可以精确表示——特别是那些分母只有2作为素数的分数(例如,1/8或1/256可以精确表示)。

它是一个浮动(双)

你不应该用它来计算钱……

我建议使用int值并使用penny

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
帮我把下面一段C++代码改写成python代码:#include "Trade.h" #include "WPrice.h" #include <algorithm> double normalCDF(double x) // Phi(-∞, x) aka N(x) { return std::erfc(-x / std::sqrt(2)) / 2; //erfc()是互补误差函数,该返回表示标准正态分布下var小于x的概率,即N(x) } CTrade::CTrade(double tick) : wp_bid(0.01), wp_ask(0.01), m_tick(tick), m_TimeRound(50) { newday(NULL); } CTrade::~CTrade() { } void CTrade::OnBook(const BTRec& btRec) { wp.setGamma(0.1); wp_bid = wp.getWP(&btRec.Bids); wp_ask = wp.getWP(&btRec.Asks); if (wp_mid > 0){ //wp_mid初始化为-1,仅遇到第一条BTRec记录时条件为false double wp_now = (wp_bid + wp_ask) / 2; //updated wp_mid int volume = btRec.volume; //volume between two orderbook records double ratio = normalCDF((wp_now - wp_mid) / (2 * m_tick)); //m_tick = tick = 0.2 double buyvolume = ratio*volume, sellvolume = (1 - ratio)*volume; m_TimeRound.update(buyvolume, sellvolume, btRec.rec_time.timestamp); //volume moving average if (mv_volume < 0) { mv_volume = volume; mv_buyvolume = buyvolume; } else{ mv_volume += 0.002*(volume - mv_volume); mv_buyvolume += 0.002*(buyvolume - mv_buyvolume); } // round trip volatility if (time_ini < 0 || btRec.rec_time.timestamp - time_ini >= time_scale){ if (time_ini>0){ double dp = wp_now - wp_ini; volatility += 0.05*(dp*dp - volatility); } time_scale = m_TimeRound.getTime() * 1000; //in milliseconds time_ini = btRec.rec_time.timestamp; wp_ini = wp_now; } } wp_mid = (wp_bid + wp_ask) / 2; } void CTrade::newday(const char* p) { wp_mid = -1; m_TimeRound.newday(p); volatility = 16 * m_tick*m_tick; time_slapse = -1, time_scale = -1, wp_ini = -1, time_ini = -1; mv_buyvolume = mv_volume = -1; }
最新发布
05-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值