C++ 17/20 的一些數值函式庫


這篇是延續之前的《C++11 的一些數值函式庫》,繼續來整理 C++17C++20 在數值函式庫上的變化。

首先,在 <numeric> 這個 header 裡面(參考),又加入了很多 template 函式可以使用,其中也包含了 gcd(對大公因數)、lcm(最小公倍數)、inner_product(內積)等等;雖然不能說沒用,但是老實說,有需要的人大概都已經有自己的方案了吧…

另外,這次也還有支援平行化reduce(),以及在平行化演算法裡面很常見的 inclusive_scan()exclusive_scan() 可以使用。

另外,C++20 也多了一個計算中點(平均值)的 midpoint();雖然基本上是個 ( a + b ) / 2 的計算,不過 std::midpoint() 的實作相對複雜、也避免了可能發生的 overflow 的問題。

下面是一個例子:

#include <cstdint>
#include <limits>
#include <numeric>
#include <iostream>
 
int main()
{
     std::uint32_t a = std::numeric_limits<std::uint32_t>::max();
     std::uint32_t b = std::numeric_limits<std::uint32_t>::max() - 2;
     std::cout
         << "a: " << a << '\n'
         << "b: " << b << '\n'
         << "Incorrect (overflow and wrapping): " << (a + b) / 2 << '\n'
         << "Correct: " << std::midpoint(a, b) << "\n\n"; }

這邊直接使用 ( a + b ) / 2 來計算的話,會因為 a + b 超過了 uint32_t 的範圍,所以結果會出現錯誤;而使用 std::midpoint() 則不會有這個問題。

而除了中點外,C++20 也在 <cmath> 中提供了一組線性內插的函式、std::lerp();他的計算基本上就是 a + t * ( b – a ) 這樣的形式。不過由於 lerp() 不是 template 的形式,所以能支援的型別就相對有限了;這點個人覺得還滿可惜的…


C++17 也在 <cmath> 中提供了一些數學的特殊函式(mathematical special functions、參考),包含了 beta、gamma、以及一些微積分函式、多項式。

不過 Heresy 必須老實說,個人對這些東西都不熟就是了。

最後,C++20 也終於透過 <numbers> 定義了包括 pi、e、ln2 這類常見的數學常數;使用方法基本上如下:

#include <numbers>
#include <iostream>
 
int main()
{
  std::cout << std::numbers::pi << "\n";
}

這邊的 std::numbers::pi 是透過 constexpr 定義的 double 型別,如果需要其他型別的話,也可以透過 std::numbers::pi_v<> 的形式來取得,例如:

float fPi = std::numbers::pi_v<float>;

(額外參考《Math constants》)


這篇大概就是這樣了。主要其實只是要記錄一下有哪些新的東西可以用,以後有需要可以回來撈而已。 XD

而很多東西太專業了,現在也就先跳過了。


參考:Numerics library

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.