转换为整数时的浮点不规则性
Floating Point Irregularity in Conversion to Integer
我有一个例程,其目的是将浮点数编码为整数(然后将其放入字节流中)。在这个过程中,信息丢失了。该例程将输出分成 3.33 的增量。
因此,0 和 3.33 之间的差距有点奇怪,因为它不是零,也不是 3.33。我决定(并非完全武断)任何非零浮动输入都应向上舍入为 3.33(同样,3.34 应向上舍入为 6.66,等等)。
一切都很好。代码如下:
function EncodeFloatingPoint (Value : Long_Float) return Integer is
Intermediate_Value : Integer;
Return_Value : Integer := 0;
begin
-- converts float into 3.33 increments
-- case 1, positive or zero
if (Value >= 0.0) then
--Ensures rounding away from zero
Intermediate_Value := Integer((Value * 100.0 + 332.99) / 333.0);
-- case 2, negative through -3.33 (up to, but not including zero)
else
-- Code omitted, is not problematic
end if;
Return_Value := Intermediate_Value;
return Return_Value;
end
当我在单元测试期间将值 0.0
传递到我的代码时,会出现此问题。单步执行时,转换结果为 3.33
而不是预期的 0.0
,我的单元测试失败了。但是,当我转到 GDB 控制台并键入 Print Integer((0.0 * 100.0 + 332.99) / 333.0)
时,结果如预期的那样为 0(用 0.0
代替值)。我可以确认 Value 输出为 0.0.
这是怎么回事?有没有更简单的方法来确保在将其转换回整数时从零舍入?
如果你查看 Language Reference Manual,你会看到浮点类型有一个属性函数 'Ceiling
,它产生 "smallest (most negative) integral value greater than or equal to X"(传递的参数)。
所以尝试:Rounded := Floating_Point_Type'Ceiling (Not_Rounded)
您正在计算 332.99 / 333.0
,大约是 0.99997。从实数到整数类型的转换轮 [ARM 4.6(33)],所以你得到 1。我假设你将其解释为 3.33。您可能必须将特殊情况设为零:
if Value > Long_Float'Pred (0.0) and Value < Long_Float'Succ (0.0) then
return 0;
end if;
(请注意,"if" 语句的条件不需要括号。)
您可能还会发现 'Remainder
属性函数很有用。您应该熟悉 ARM A.5.3 中的所有 floating-point 属性(实际上是 ARM A 中的所有标准库)。
看来您正在创建自己的 fixed-point 类型,其值为 3.33。为什么不让语言为您做到这一点?
Result_Delta : constant := 3.33;
type Result_Value is delta Result_Delta
range Integer'First * Result_Delta .. Integer'Last * Result_Delta
with Small => Result_Delta;
我有一个例程,其目的是将浮点数编码为整数(然后将其放入字节流中)。在这个过程中,信息丢失了。该例程将输出分成 3.33 的增量。
因此,0 和 3.33 之间的差距有点奇怪,因为它不是零,也不是 3.33。我决定(并非完全武断)任何非零浮动输入都应向上舍入为 3.33(同样,3.34 应向上舍入为 6.66,等等)。
一切都很好。代码如下:
function EncodeFloatingPoint (Value : Long_Float) return Integer is
Intermediate_Value : Integer;
Return_Value : Integer := 0;
begin
-- converts float into 3.33 increments
-- case 1, positive or zero
if (Value >= 0.0) then
--Ensures rounding away from zero
Intermediate_Value := Integer((Value * 100.0 + 332.99) / 333.0);
-- case 2, negative through -3.33 (up to, but not including zero)
else
-- Code omitted, is not problematic
end if;
Return_Value := Intermediate_Value;
return Return_Value;
end
当我在单元测试期间将值 0.0
传递到我的代码时,会出现此问题。单步执行时,转换结果为 3.33
而不是预期的 0.0
,我的单元测试失败了。但是,当我转到 GDB 控制台并键入 Print Integer((0.0 * 100.0 + 332.99) / 333.0)
时,结果如预期的那样为 0(用 0.0
代替值)。我可以确认 Value 输出为 0.0.
这是怎么回事?有没有更简单的方法来确保在将其转换回整数时从零舍入?
如果你查看 Language Reference Manual,你会看到浮点类型有一个属性函数 'Ceiling
,它产生 "smallest (most negative) integral value greater than or equal to X"(传递的参数)。
所以尝试:Rounded := Floating_Point_Type'Ceiling (Not_Rounded)
您正在计算 332.99 / 333.0
,大约是 0.99997。从实数到整数类型的转换轮 [ARM 4.6(33)],所以你得到 1。我假设你将其解释为 3.33。您可能必须将特殊情况设为零:
if Value > Long_Float'Pred (0.0) and Value < Long_Float'Succ (0.0) then
return 0;
end if;
(请注意,"if" 语句的条件不需要括号。)
您可能还会发现 'Remainder
属性函数很有用。您应该熟悉 ARM A.5.3 中的所有 floating-point 属性(实际上是 ARM A 中的所有标准库)。
看来您正在创建自己的 fixed-point 类型,其值为 3.33。为什么不让语言为您做到这一点?
Result_Delta : constant := 3.33;
type Result_Value is delta Result_Delta
range Integer'First * Result_Delta .. Integer'Last * Result_Delta
with Small => Result_Delta;