2

我有一些代码使用普通数学而不是字符串数学来获取 Double 的前导值(非零)......

例如:
0.020 将返回 2
3.12 将返回 3
1000返回 1

我现在的代码是:

LeadingValue := Trunc(ResultValue * Power(10, -(Floor(Log10(ResultValue)))))

但是,当 ResultValue 为 1000 时,LeadingValue 最终为 0。

我可以做些什么来解决我假设是由浮点错误引起的这个问题?

谢谢。

4

4 回答 4

1

我很好奇为什么你不能/不会为此使用字符串操作。你能进一步解释一下吗?

解决问题最明显的方法是将数字转换为字符串并找到第一个非零数字。

于 2010-05-30T23:44:15.833 回答
1

绕过舍入问题的一种可能方法:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Math;

function LeadingValue(num: extended): integer;
const
  ExtendedResolution = 1E-19 * 1000; // from Math
begin
  num := Abs(num);
  Result := Trunc(num * Power(10, -(Floor(Log10(num)))) + ExtendedResolution);
end;

begin
  try
    Writeln(LeadingValue(0.02));
    Writeln(LeadingValue(3.12));
    Writeln(LeadingValue(1000));
    Writeln(LeadingValue(0.9999999999));
    Writeln(LeadingValue(1.0000000001));
    Writeln(LeadingValue(-0.02));
    Writeln(LeadingValue(-3.12));
    Writeln(LeadingValue(-1000));
    Writeln(LeadingValue(-0.9999999999));
    Writeln(LeadingValue(-1.0000000001));
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
于 2010-05-31T06:37:27.653 回答
0

如果你除而不是乘,它会修复你的测试用例。总体而言,它将产生更好的结果,因为“功率”结果不会有分数值。恐怕它可能没有 100% 的案例覆盖率,但除非提出更好的解决方案,否则这应该比你拥有的更好。

function Func(Value : Double) : Integer;
begin
  Result := Trunc(Value / Power(10, (Floor(Log10(Value)))))
end;
于 2010-05-31T17:01:21.477 回答
0

您将无法使用浮点数学以 100% 的准确度做到这一点。您需要做的基本上是将二进制浮点值转换为十进制字符串。准确执行此操作的例程,例如David Gay 的 dtoa.c,使用高精度(整数)算术。

于 2010-06-01T01:10:10.320 回答