簡體   English   中英

Math.Log是否以避免log(1 + x)精度損失的方式實現?

[英]Is Math.Log implemented in a way to avoid loss of precision for log(1 + x)?

我正在將一些C#代碼轉換為C ++,其中包含Math.Log(1 + x)Math.Log(1 + x) ,其中x可以是一個非常小的值,接近於零。 我遇到了建議(在C ++中),建議在處理log(1 + x)時使用std::log1p ,其中x接近零,即避免精度損失

C#/。NET Math.Log方法是否以類似避免精度損失的方式實現? 我找不到.NET API參考中引用的類似Math.Log1p()函數。

不,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);
}

如果您需要的目標是.NET版本低於4.0,則可以考慮將DllImport聲明更改為使用“ ucrtbase.dll”。

可能值得注意的是,我無法在此代碼上獲得一致的性能。 將x64放在我的便攜式筆記本電腦上的C#和C上,每次調用約140納秒。 但是在將x86定位為225與40時,看到了很大的不同。巨大的不同,我對此沒有很好的解釋。

查看參考實現Log()只是調用一個外部函數Log() ,我認為這只是指令集的對數函數。

流行的Accord.Math庫確實具有log1p函數,該函數非常簡單 ,可以通過以下一種代碼實現:

static double log1p(double x)
    => Math.Abs(x) > 1e-4 ? Math.Log(1.0 + x) : (-0.5 * x + 1.0) * x;
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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM