【问题标题】:Is Math.Log implemented in a way to avoid loss of precision for log(1 + x)?Math.Log 是否以某种方式实现以避免 log(1 + x) 的精度损失?
【发布时间】:2018-04-24 21:15:03
【问题描述】:

我正在将一些 C# 代码转换为 C++,其中包含 Math.Log(1 + x) 的用法,其中 x 可以是接近于零的非常小的值。在处理log(1 + x) 时,我遇到了使用std::log1p 的建议(在C++ 中),其中x 接近于零,即to avoid loss of precision

C#/.NET Math.Log 方法是否以同样避免精度损失的方式实现?我在 .NET API 参考中找不到类似的 Math.Log1p() 函数。

【问题讨论】:

  • 自己试试?
  • MSDN 对此事有什么要说的吗?
  • @Plutonix - 我尝试搜索 log1p 但找不到任何东西。 Math.Log 条目的侧边栏中没有类似的内容:msdn.microsoft.com/en-us/library/system.math.log(v=vs.110).aspx
  • @Steve 我现在没有测试 C#/.NET 代码的方法,我在 linux 机器上编写 C++(是的,我想我可以安装 Mono 等)
  • 在我看来精度损失不在函数内部,而是在准备输入参数时。

标签: c# c++ .net precision logarithm


【解决方案1】:

不,Math.Log() 使用 C 库函数 log() 来完成它的工作。 log1p() 实际上包含在 CLR 使用的 CRT 库中,但它没有通过框架公开。你可以通过 pinvoke 声明来解决这个问题:

using System;
using System.Runtime.InteropServices;

public static class Math {
    public static double Log1p(double arg) {
        if (arg < -1.0) throw new ArgumentException();
        return log1p(arg);
    }

    [DllImport("msvcr120_clr0400.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern double log1p(double arg);
}

如果您需要针对低于 4.0 的 .NET 版本,请考虑将 DllImport 声明更改为使用“ucrtbase.dll”。

值得注意的是,我无法在此代码上获得一致的性能。在我的 poky 笔记本电脑上针对 C# 和 C 上的 x64 目标,我每次调用大约 140 纳秒。但是在针对 x86、225 和 40 时看到了很大的差异。很大的差异,我对此没有很好的解释。

【讨论】:

    【解决方案2】:

    查看reference implementationLog() 只是调用了一个外部函数Log(),我认为它只是指令集的对数函数。

    流行的库Accord.Math确实有一个log1p函数pretty simple,可以通过以下单行实现:

    static double log1p(double x)
        => Math.Abs(x) > 1e-4 ? Math.Log(1.0 + x) : (-0.5 * x + 1.0) * x;
    

    【讨论】:

    • 我不知道有任何 CPU 有 LOG 指令。
    【解决方案3】:
    double VerySmall = .0000000000000002;
    double TooSmall = .0000000000000001;
    Console.WriteLine("{0} {1} {2}", Math.Log(1 + VerySmall), Math.Log(1 + TooSmall), log1p(TooSmall));
    
    static double log1p(double x)
          => Math.Abs(x) > 1e-4 ? Math.Log(1.0 + x) : (-0.5 * x + 1.0) * x;
    

    在 Windows 上运行的 .NET framework 4.6.1 中,这段代码的输出是:

    2.22044604925031E-16 0 1E-16
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 2021-12-10
      • 2011-10-13
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-05-05
      相关资源
      最近更新 更多