论坛首页 Java企业应用论坛

什么时候使用assumption?

浏览 11241 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-02-18  
pojo 写道
我的fromAmount(double total, double amount)和你的一样是有判断的:
    public static Portion fromAmount(double total, double amount)
    {
        if (total== 0)
            return new Portion(0, 0);
        return new Portion(total, weight/total);
    }
所以fromAmount(777, 1).getAmount() == 1

至于fromAmount(0, 1),我认为最好的办法是抛出异常,因为这是一个不合理的输入,如果让它进入系统,会引起麻烦的。

fromAmount(777, 1).getAmount()在你的方案里很可能返回0.9999999。我期望它返回1。

至于说total为0会造成麻烦。也许吧。但是这个遗留系统里面到处都是对total==0的判断,即使会引起麻烦,也已经是麻烦了。把这个改成抛出异常,虽然可能干净,但是对系统行为的改变是巨大的。
0 请登录后投票
   发表时间:2007-02-19  
ajoo 写道
complystill 写道
如果需要精确的计算一致性本来就不能用 double, 既然用了double就不应该期望任意运算结果都落在一定的误差范围内.

我觉得:

如果需要很高精度, 就必须把double换成BigDecimal.

如果需要绝对精度, 就要用像IBM的无误差运算库之类的专门解决方案.

double精度造成的suprise不是应用程序的问题, 而是 IEEE FP 规范的问题.

如果说项目需求要求在应用程序里实现基于double的精度保障, 那楼主的方案很好, 但是如果没有这方面的明确需求, 就没有必要了.

double是系统范围内采用的。但是我并不认为采用了double,就可以容忍val != val,或者new Double(val).doubleValue()!=val的情况出现。


ieee标准并没有造成new Double(val).doubleValue()!=val。同样,我也希望fromAmount(total, val).getAmount==val。觉得这个要求不过分。


这个要求感觉不是客户提出来的吧, 用了double的话, 只要稍微有点计算, 就不能期望恒等了呀, val == val/777*777 这个就不能成立了. fromAmount(total, val) 也是逻辑封装, 从外部来看如果 getAmount() 的结果要和它恒等联系起来, 也可以算个高耦合了吧. 至少 getAmount() 的定义, 应该不至于要规范到和构造方法的联系上去吧. 作为构造参数的val值与作为getAmount()返回的值是两个不同概念, 逻辑上是有联系, 但这个联系应该是自然松耦合的联系, 没必要是作为特例而保障出来的联系吧.

有限精度的浮点比较总是需要加上一个容忍范围的, 在机器级别, 甚至 0 == -0 都不成立. 如果其它地方用了 double 的 == 比较, 那或者是非严重错误, 或者是有该上下文的assumption而有意去写成的. 而只有刻意去 fromAmount(total, val).getAmount() 以后马上跟传的 val 进行恒等比较才会觉得蹊跷, 实际程序里真的有这样的逻辑吗?

在这一点上刻意减少误差, 是没法防止系统里其它地方因double精度导致的误差累积的, 到一定程度该出错的时候还是会出错, 倒是这里对精度的特殊处理和其它地方不一致, 反而可能给将来的问题追踪定位增加困惑呢. 虽然如果真的发生了, 这种困惑本来就会很大, 增加一点无足轻重, 但投入的成本也没得到什么好处啊.
0 请登录后投票
   发表时间:2007-02-19  
complystill 写道


在这一点上刻意减少误差, 是没法防止系统里其它地方因double精度导致的误差累积的, 到一定程度该出错的时候还是会出错, 倒是这里对精度的特殊处理和其它地方不一致, 反而可能让将来的问题追踪定位更加困惑呢.

嗯。我还是向标准的Double看齐。new Double(val).doubleValue()==val,也没有造成什么更困惑的问题。val==val也没有造成问题。虽然val!=val*777/777。反倒是如果允许val!=val才会造成严重的问题。

我觉得这两者间还是有本质的不同的。经过计算而导致误差客户可以接受,但是没有计算而直接因为内部实现上的一些细节而导致了误差觉得就非常不好。客户可能不关心,但是也可能关心啊。有必要在这里使用一个assumption么?

要说这个不是需求,但是必须有误差也不是需求吧?无论如何,没误差不是总比有误差好?val==val毕竟也满足abs(val-val)<0.1,对么?也就是说,没有误差并不影响你按照有误差的方法来使用它,而相反则不是。

我觉得在两个实现难度上相似的情况下,当然优先选择assumption少的,适应能力高的。
0 请登录后投票
   发表时间:2007-02-19  
写了段Java程序试试:
    public static void main(String[] args)
    {
        System.out.println("new Double(0.0d).equals(-0.0d) ? "
                + new Double(0.0d).equals(-0.0d));
    }

结果呢? false

用double的时候这种都容忍了, 感觉有点像Object的 == 和 equals(Object o) 的差别了.
0.0d == -0.0d 是 true, 但是 Double.equals 里面是按位比较, 最后就不相等了.
要是再考虑上 NaN 和 正/负 INFINITY 潜在问题就更多了.

另外实现难度可能写代码功夫不用多花多少, 但是测试和将来维护改bug都增加了一些工作量. 我是感觉不太值得, 至少没看过这段程序的人在不知情的情况下第一次见了会先愣一下, 奇怪怎么还用得着这么搞..

我感觉还是是计算机处理整数相对比较完美, 写多了系统程序和一般应用程序, 就会觉得浮点数也应该差不多, 头一次发现居然还有不能相等的情况有点难以接受, 大概做多了就好了吧.
0 请登录后投票
   发表时间:2007-02-19  
complystill 写道
写了段Java程序试试:
    public static void main(String[] args)
    {
        System.out.println("new Double(0.0d).equals(-0.0d) ? "
                + new Double(0.0d).equals(-0.0d));
    }

结果呢? false

用double的时候这种都容忍了, 感觉有点像Object的 == 和 equals(Object o) 的差别了.
0.0d == -0.0d 是 true, 但是 Double.equals 里面是按位比较, 最后就不相等了.
要是再考虑上 NaN 和 正/负 INFINITY 潜在问题就更多了.

另外实现难度可能写代码功夫不用多花多少, 但是测试和将来维护改bug都增加了一些工作量. 我是感觉不太值得, 至少没看过这段程序的人在不知情的情况下第一次见了会先愣一下, 奇怪怎么还用得着这么搞..

我感觉还是是计算机处理整数相对比较完美, 写多了系统程序和一般应用程序, 就会觉得浮点数也应该差不多, 头一次发现居然还有不能相等的情况有点难以接受, 大概做多了就好了吧.

这个不一样吧?0d!=-0d,和val!=val还是两个性质吧?毕竟前者还是通过了运算的,对么?

你觉得new Double(val).doubleValue()!=val可以接受么?
0 请登录后投票
   发表时间:2007-02-19  
这样似乎是说不能接受在 fromAmount(total, val) 内部对 val 进行运算了哦.

new Double(val) != new Double(val)  这个基于Java的话想不接受也不行啊. 虽然和 new Double(val).doubleValue() 还是有差别, 但都是经过了 对象类型 对 基本类型 的封装这个本质是一样的吧.

另外, 也考虑特殊情况, 如果 val 的取值是 Double.NaN, 那么 new Double(val).doubleValue() 就是 != val 的:
        double val = Double.NaN;
        System.out.println("NaN == NaN ? "
                + (new Double(val).doubleValue() == val));

结果会是 false
0 请登录后投票
   发表时间:2007-02-19  
complystill 写道
这样似乎是说不能接受在 fromAmount(total, val) 内部对 val 进行运算了哦.

new Double(val) != value 这个基于Java的话想不接受也不行啊, 这是用了autoboxing以后的写法, 按以前的写法是: new Double(val) != new Double(val)
虽然和 new Double(val).doubleValue() 还是有差别, 但都是经过了 对象类型 对 基本类型 的封装这个本质是一样的吧.


btw. 如果 val 的取值是 Double.NaN, 那么 new Double(val).doubleValue() 就是 != val 的:
        double val = Double.NaN;
        System.out.println("NaN == NaN ? "
                + (new Double(val).doubleValue() == val));

结果会是 false

不是。我不是说boxing。是说new Double(val).doubleValue()==val。
也不是说fromAmount(total, amount)内部就不能有计算。内部有什么,我作为用户不那么关心。但是从接口上fromAmount(total, amount).getAmount() != amount就感觉有点怪。

0 请登录后投票
   发表时间:2007-02-19  
觉得奇怪是正常的啦, 但是为了浮点规范本身的限制去增加自己程序复杂性就不值得了. 如果不是那么直白, 而是间接隐含的碰到 fromAmount(total, amount).getAmount() != amount 的情况和 碰到 1.0d/777*777 != 1.0d 的惊讶程度差不了多少的.

其实二进制浮点数还有很多别的陷阱呢, 搜索过程中发现这篇文章: http://www.concentric.net/~Ttwang/tech/javafloat.htm
0 请登录后投票
   发表时间:2007-02-19  
complystill 写道
觉得奇怪是正常的啦, 但是为了浮点规范本身的限制去增加自己程序复杂性就不值得了. 如果不是那么直白, 而是间接隐含的碰到 fromAmount(total, amount).getAmount() != amount 的情况和 碰到 1.0d/777*777 != 1.0d 的惊讶程度差不了多少的.

呵呵。我是觉得惊讶程度还是很有差别的。规范本身所带来的惊讶我管不了。但是我不希望我的代码放大这种惊讶。
同时觉得实现复杂性没什么区别。:)
0 请登录后投票
   发表时间:2007-08-15  
引用
但是,pair对这种设计感觉不舒服,他不喜欢把逻辑放在静态工厂方法中。


他的理由是什么,应该很有道理啊
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics