NO.2 找零时刻

Java谜题1:表达式谜题

NO.2 找零时刻


public class Change{
	public static void main(String args[]){
		System.out.println(2.00 - 1.10);
	}
}


打印结果:0.8999999999999999根据Double.toString 文档中所设定的将double 类型的值转换为字符串的规则,该程序打印出来的小数,是足以将double 类型的值与最靠近它的临近值区分出来的最短的小数,它在小数点之前和之后都至少有一位。因此,看起来,该程序应该打印0.9 是合理的。这么分析可能显得很合理,但是并不正确。

问题在于1.1 这个数字不能被精确表示成为一个double,因此它被表示成为最接近它的double 值。并不是所有的小数都可以用二进制浮点数来精确表示的。

解决该问题的一种方式是使用某种整数类型,例如int 或long,并且以分为单位来执行计算。解决该问题的另一种方式是使用执行精确小数运算的BigDecimal。它还可以通过JDBC 与SQL DECIMAL 类型进行互操作。这里要告诫你一点: 一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。

后一个构造器将用它的参数的“精确”值来创建一个实例:new BigDecimal(.1)将返回一个表示0.100000000000000055511151231257827021181583404541015625  的BigDecimal。

import java.math.BigDecimal;
public class Change1{
	public static void main(String args[]){
		System.out.println(new BigDecimal("2.00").
		subtract(new BigDecimal("1.10")));
	}
}

Java 并没有为BigDecimal 提供任何语言上的支持。使用BigDecimal 的计算很有可能比那些使用原始类型的计算要慢一些。


总之, 在需要精确答案的地方,要避免使用float 和double;对于货币计算,要使用int、long 或BigDecimal。
对于语言设计者来说,应该考虑对小数运算提供语言支持。
一种方式是提供对操作符重载的有限支持,以使得运算符可以被塑造为能够对数值引用类型起作用,例如BigDecimal。
另一种方式是提供原始的小数类型,就像COBOL 与PL/I 所作的一样。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该工程可以分为以下几个部分: 1. 货币识别模块:根据输入的信号判断输入的货币面额是100、50、20还是10,并将结果输出。 2. 找零模块:根据输入的信号和货币识别模块的输出,计算需要找零的金额,并将结果输出。 3. 状态机模块:控制整个工程的状态转移。 下面是一个可能的实现: ```verilog module currency_changer( input clk, // 时钟信号 input rst, // 复位信号 input [7:0] money_in, // 输入的金额 input [1:0] coin_type, // 货币类型:00-100元,01-50元,10-20元,11-10元 output reg [7:0] change, // 找零金额 output reg done // 工程完成信号 ); // 定义状态机状态 localparam [2:0] IDLE = 3'b000; localparam [2:0] MONEY_REC = 3'b001; localparam [2:0] CALC_CHANGE = 3'b010; localparam [2:0] CHANGE_OUT = 3'b011; localparam [2:0] OPTIMIZE = 3'b100; // 定义状态机变量 reg [2:0] state, next_state; // 货币面额识别模块 reg [1:0] cur_coin; always @(*) begin case (coin_type) 2'b00: cur_coin = 2'b00; // 100元 2'b01: cur_coin = 2'b01; // 50元 2'b10: cur_coin = 2'b10; // 20元 2'b11: cur_coin = 2'b11; // 10元 default: cur_coin = 2'b00; endcase end // 找零模块 wire [7:0] change_to_give; always @(*) begin case (cur_coin) 2'b00: change_to_give = money_in - 100; 2'b01: change_to_give = money_in - 50; 2'b10: change_to_give = money_in - 20; 2'b11: change_to_give = money_in - 10; default: change_to_give = 0; endcase end // 状态机 always @(posedge clk, posedge rst) begin if (rst) begin state <= IDLE; end else begin state <= next_state; end end // 状态转移逻辑 always @(*) begin next_state = state; case (state) IDLE: begin if (money_in > 0) begin next_state = MONEY_REC; end end MONEY_REC: begin next_state = CALC_CHANGE; end CALC_CHANGE: begin if (change_to_give > 0) begin next_state = CHANGE_OUT; end else begin next_state = OPTIMIZE; end end CHANGE_OUT: begin next_state = OPTIMIZE; end OPTIMIZE: begin next_state = IDLE; end default: next_state = IDLE; endcase end // 完成信号 always @(*) begin done = (state == IDLE); end // 找零输出和优化 reg [7:0] change_reg; always @(posedge clk) begin if (state == CHANGE_OUT) begin change_reg <= change_to_give; end else if (state == OPTIMIZE) begin change <= change_reg - 10; change_reg <= 0; end end endmodule ``` 该代码使用了一个状态机来控制整个工程的状态转移,实现了货币识别和找零的功能。在每一个时钟上升沿时,根据当前状态和输入信号计算出下一个状态,并将状态保存到 `next_state` 中。在状态转移的同时,还会计算出需要找零的金额,并将结果保存到 `change_to_give` 中。在状态机进入 `CHANGE_OUT` 状态时,将 `change_to_give` 赋值给 `change_reg`,并在每个时钟上升沿时更新 `change` 的值,直到状态机进入 `OPTIMIZE` 状态,此时将 `change_reg` 减去10,得到最终的找零金额,并将 `change_reg` 清零。 最后,使用 Vivado 工具对代码进行优化,并将优化后的代码输出即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值