`

Puzzel2:Time for a Change

阅读更多

Consider the following word problem:

 

考虑以下word problem:

Tom goes to the auto parts store to buy a spark plug that costs $1.10, but all he has in his wallet are two-dollar bills. How much change should he get if he pays for the spark plug with a two-dollar bill?

 

Tom去汽车配件店买一个价格为 $1.10的火花塞,但他口袋里只有一张两美元的钞票。如果他用这些钱买火花塞会得到多少找零?

Here is a program that attempts to solve the word problem. What does it print?

 

这里是一个企图解决此问题的程序,它会打印出什么?

public class Change {

    public static void main(String args[]) {

        System.out.println(2.00 - 1.10);

    }

}


Solution 2: Time for a Change

Naively, you might expect the program to print 0.90, but how could it know that you wanted two digits after the decimal point? If you know something about the rules for converting double values to strings, which are specified by the documentation for Double.toString [Java-API], you know that the program prints the shortest decimal fraction sufficient to distinguish the double value from its nearest neighbor, with at least one digit before and after the decimal point. It seems reasonable, then, that the program should print 0.9. Reasonable, perhaps, but not correct. If you ran the program, you found that it prints 0.8999999999999999.

 

你也许会天真地期待程序打印出 0.90,但是程序怎么知道你希望得到小数点后两位数?如果你知道一些double型转换为string型的规则,在java-api文档里有详细的double.tostring说明[Java-API],,你了解到程序打印出最短十进制片段,这个数字片段足够与其最近的邻居区别开来,并且在小数点前后各有至少一位。看上去很合理,那么程序应当打印出0.9。合理的,可能是,但不正确。如果你跑这段程序,你发现它打印出0.8999999999999999。

The problem is that the number 1.1 can't be represented exactly as a double, so it is represented by the closest double value. The program subtracts this value from 2. Unfortunately, the result of this calculation is not the closest double value to 0.9. The shortest representation of the resulting double value is the hideous number that you see printed.

 

问题其实是数字1.1作为double型数据不能被精确表现,所以它其实是被一个最近似的double值来表现。程序从2减去这个值。计算结果不幸不是0.9的最近似值。结果最短表现值是你看到的令人惊讶的数字。

 

More generally, the problem is that not all decimals can be represented exactly using binary floating-point. If you are using release 5.0 or a later release, you might be tempted to fix the program by using the printf facility to set the precision of the output:

更一般的,问题是用二进制浮点不能精确表现所有十进制数。如果你用了5.0或以上的版本,你可以用print facility来修正程序设置它的输出精度
// Poor solution - still uses binary floating-point!
//差劲的解法-仍然使用二进制浮点

System.out.printf("%.2f%n", 2.00 - 1.10);

This prints the right answer but does not represent a general solution to the underlying problem: It still uses double arithmetic, which is binary floating-point. Floating-point arithmetic provides good approximations over a wide range of values but does not generally yield exact results. Binary floating-point is particularly ill-suited to monetary calculations, as it is impossible to represent 0.1—or any other negative power of 10—exactly as a finite-length binary fraction [EJ Item 31].

 

这将打印正确的结果但并未对根本问题有一般的解决;它仍然用二进制浮点的double运算。浮点运算提供了广泛的好的近似但并不会一般性的得出精确的结果。二进制浮点尤其不合适货币计算,因为不可能将0.1或其它任何10的负数次方数精确表现为有限长度的二进制片段。[EJ Item 31].

 

One way to solve the problem is to use an integral type, such as int or long, and to perform the computation in cents. If you go this route, make sure the integral type is large enough to represent all the values you will use in your program. For this puzzle, int is ample. Here is how the println looks if we rewrite it using int values to represent monetary values in cents. This version prints 90 cents, which is the right answer:

 

解决此问题的一个方法是用整型数据,如int或long,且用cents执行计算。如果你这么做,确保整型足够大来表现所有你将在程序中用到的值。这个谜题中,int足够了。下面是如何使用int值来表现cents的数值来重新写程序,用println看结果。这个版本打印出90 cents,这是个正确的结果。

System.out.println((200 - 110) + " cents");

 

Another way to solve the problem is to use BigDecimal, which performs exact decimal arithmetic. It also interoperates with the SQL DECIMAL type via JDBC. There is one caveat: Always use the BigDecimal(String) constructor, never BigDecimal(double). The latter constructor creates an instance with the exact value of its argument: new BigDecimal(.1) returns a BigDecimal representing 0.1000000000000000055511151231257827021181583404541015625. Using BigDecimal correctly, the program

 

另一方法是用bigdecimal,它执行精确十进制运算。它通过jdbc与sql的decimal类型互相操作。有一个附加说明:总是用bigdecimal(string),绝不用bigdecimal(double)。后者创建一个其参数的精确实例;new BigDecimal(.1)返回一个BigDecimal表现为:0.1000000000000000055511151231257827021181583404541015625。正确使用BigDecimal,程序为:

 

prints the expected result of 0.90:

import java.math.BigDecimal;

public class Change {

    public static void main(String args[]) {

        System.out.println(new BigDecimal("2.00").

                           subtract(new BigDecimal("1.10")));

    }

}

 

This version is not terribly pretty, as Java provides no linguistic support for BigDecimal. Calculations with BigDecimal are also likely to be slower than those with any primitive type, which might be an issue for some programs that make heavy use of decimal calculations. It is of no consequence for most programs.

 

这个版本不是非常漂亮,因为java对BigDecimal提供no linguistic的支持。BigDeimal的计算都比那些使用原始数据类型的要慢,这也许会是某些程序大量使用decimal计算时的问题。这是大多数程序的重点。

 

In summary, avoid float and double where exact answers are required; for monetary calculations, use int, long, or BigDecimal. For language designers, consider providing linguistic support for decimal arithmetic. One approach is to offer limited support for operator overloading, so that arithmetic operators can be made to work with numerical reference types, such as BigDecimal. Another approach is to provide a primitive decimal type, as did COBOL and PL/I.

 

总而言之,需要精确结果时避免float与double;对于货币计算,用int,long或BigDecimal。对于语言设计者,考虑对BigDecimal运算提供linguistic支持。一个方法是提供对操作符重载提供有限支持,这样一来运算符能够被用来与数字相关类型,如BigDecimal。另一方法是提供十进制数的原始数据类型,就如同COBOL和PL/I中那样。

分享到:
评论

相关推荐

    Java™ Puzzlers: Traps, Pitfalls, and Corner Cases.chm

    Puzzle 2: Time for a Change Puzzle 3: Long Division Puzzle 4: It's Elementary Puzzle 5: The Joy of Hex Puzzle 6: Multicast Puzzle 7: Swap Meat Puzzle 8: Dos Equis Puzzle 9: Tweedledum Puzzle 10: ...

    Java解惑(中文版)

    puzzle 2:time for a change puzzle 3:long pision puzzle 4:it s elementary puzzle 5:the joy of hex puzzle 6:multicast puzzle 7:swap meat puzzle 8:dos equis puzzle 9:tweedildum puzzle 10:...

    Java解惑(谜题)CHM中英文双版本

    Puzzle 2: Time for a Change Puzzle 3: Long Division Puzzle 4: It's Elementary Puzzle 5: The Joy of Hex Puzzle 6: Multicast Puzzle 7: Swap Meat Puzzle 8: Dos Equis Puzzle 9: Tweedledum ...

    有关Java编程方面的几点解惑

    - **Puzzle 2: Time for a Change(改变之时)** - 此谜题揭示了Java中日期和时间处理中的一些陷阱,尤其是在处理时区差异时可能出现的问题。 - **Puzzle 3: Long Division(长除法)** - 该谜题探讨了Java中长...

    PuzzleMix:PyTorch的“ Puzzle Mix混合体”官方实施

    引用这项工作@inproceedings{kimICML20, title= {Puzzle Mix: Exploiting Saliency and Local Statistics for Optimal Mixup}, author = {Kim, Jang-Hyun and Choo, Wonho and Song, Hyun Oh}, booktitle = {...

    react-native-picture-puzzle::atom_symbol::puzzle_piece:图片拼图组件

    :atom_symbol: :puzzle_piece: 图片拼图组件。 支持 , 和 。 :rocket: 入门 使用 : yarn add react-native-picture-puzzle :writing_hand: 用法 import React from 'react' ; import { PicturePuzzle , ...

    puzzletime:中小企业的开源时间跟踪和资源计划Web应用程序

    欢迎来到PuzzleTime PuzzleTime是面向中小企业的开源时间跟踪和资源计划Web应用程序。 发展 PuzzleTime是一个运行在Ruby> = 2.2.2和Rails 5上的Ruby on Rails应用程序。要开始使用,请在获得PuzzleTime副本后,在主...

    Puzzle for 3dMax拼图随机生成器工具下载

    3DMAX拼图随机生成器(英文:Puzzle),是一款为3dsMax开发的拼图建模小工具,可以随机创建可编辑多边形3D拼图对象。可批量生成阵列。 安装方法:点击3dmax主菜单-脚本-运行脚本,选择Puzzle-1.0.0-zh_CN运行即可。

    A_game_for_puzzle_picture_puzzle_for_9.zip

    A_game_for_puzzle_picture_puzzle_for_9

    Impostor Sort Puzzle 2 冒名顶替者排序谜题2 Unity小人排序游戏项目源码C#

    Impostor Sort Puzzle 2: Sort It 2D 很容易玩,但有时确实具有挑战性。 您还可以通过这款益智游戏放松或训练您的大脑。 怎么玩: 按颜色对冒名顶替者进行分类,以确保每个人的安全。 就像你做球排序一样。 当你把...

    8-puzzle:实施8个益智游戏python 8拼图实施BFS,DFS,贪婪和A 搜索8个难题解决方案.zip

    4. **A*搜索**:A*搜索是启发式搜索的一种,结合了BFS的最优性与DFS的效率。它使用一个评估函数(通常是曼哈顿距离或汉明距离)来估计从当前状态到目标状态的最优路径。A*搜索既考虑了到达目标的距离,也考虑了从...

    AI: Eight puzzle by A star algorithm with C++

    《使用C++实现A*算法解决八数码拼图问题》 在信息技术领域,人工智能(AI)是当前最为活跃的研究方向之一。八数码拼图(又称滑块拼图)是AI中经典的搜索问题,它考察了如何通过有效的算法来解决路径规划问题。本...

    8puzzle & a* pathfinder

    《8 Puzzle 拼图与 A* 路径寻找算法详解》 8 Puzzle 是一个经典的数学游戏,它由一个3x3的格子组成,其中8个格子上分别标有数字1到8,而第9个格子为空。玩家的目标是通过交换相邻的数字,将初始状态调整为预设的...

    PuzzleGame:ue4 c ++制作的益智游戏

    《PuzzleGame: UE4 C++制作的益智游戏》 在游戏开发领域,Unreal Engine 4(简称UE4)是一款广泛使用的强大游戏引擎,它支持多种编程语言,其中C++是其核心编程语言之一。本项目"**PuzzleGame**"是一个使用UE4和C++...

    n_puzzle_state

    2. **A*搜索算法**:A*算法的核心在于使用了启发式函数(通常用H(n)表示),它提供了一个从当前节点到目标节点的最佳估计代价。算法的主要步骤包括: - 初始化开放列表(包含起始节点)和关闭列表。 - 计算当前...

    Puzzle Cam:改造创业板。 正方形不在右下角(第 16 个)-开源

    终端命令:java -jar sga-puzzle.jar OSX 1. 安装 Java8 2. 安装 ant 3. $brew edit opencv -> Change DBuild-with-java=ON 4. $brew install opencv --build-from-source 5 . 安装应用程序 6. 享受! 安卓棒棒糖++...

    Puzzle16:一个Puzzle16视觉基础项目-开源

    我开发的有趣的Puzzle代码,仅用于娱乐用途。

    A-star-8-number.rar_8 puzzle_8数码_a star_number puzzle_puzzle 8

    标题"A-star-8-number.rar_8 puzzle_8数码_a star_number puzzle_puzzle 8"以及描述中的关键信息表明,这是一个关于使用A*算法解决8数码难题的项目。8数码难题,也被称为滑动拼图,是一款经典的逻辑游戏,玩家需要...

    人工智能应用(A*) - Puzzle - 8:实现A*算法解决Puzzle-8。-matlab开发

    本程序将 A* 算法应用于拼图 8。 谜题 8: 这是一个简单的滑动游戏,孩子们用它来解决。 同样的滑动游戏成为使用计算机解决的巨大挑战。 通过使用各种组合来解决的传统方法是很长的过程。 AI 的算法 A* (A-Star) ...

    PuzzleGame:基于DCD(数字电路设计)的益智游戏

    《PuzzleGame:基于DCD(数字电路设计)的益智游戏》是一款融合了数字电路设计概念的创新益智游戏。在游戏中,玩家需要利用逻辑思维和数字电路的基础知识来解决各种挑战,以此提升对电子工程的理解和兴趣。下面将详细...

Global site tag (gtag.js) - Google Analytics