在C++中键入安全的物理操作

Type safe physics operations in C++

本文关键字:操作 安全 C++      更新时间:2023-10-16

物理单元定义为单独的类型并在这些类型之间定义有效操作是否C++有意义?

引入大量类型和大量运算符重载而不是仅使用普通浮点值来表示它们有什么优势吗?

例:

class Time{...};
class Length{...};
class Speed{...};
...
Time operator""_s(long double val){...}
Length operator""_m(long double val){...}
...
Speed operator/(const Length&, const Time&){...}

TimeLengthSpeed只能作为来自不同运算符的返回类型创建?

C++将物理单位定义为单独的类型并在这些类型之间定义有效操作是否有意义?

绝对。标准的 Chrono 库已经对时间点和持续时间执行此操作。

引入大量类型和大量运算符重载而不是仅使用普通浮点值来表示它们有什么优势吗?

是的:您可以使用类型系统来捕获错误,例如在编译时将质量添加到距离,而不会增加任何运行时开销。

如果您不想自己定义类型和运算符,Boost 有一个单位库。

我真的会为此推荐boost::units。它执行所有转换编译时,如果您尝试使用错误的维度,它还会给您一个编译时错误伪代码示例:

length l1, l2, l3;
area a1 = l1 * l2; // Compiles
area a2 = l1 * l2 * l3; // Compile time error, an area can't be the product of three lengths.
volume v1 = l1 * l2 * l3; // Compiles

我已经走上了这条路。优点都是普通的众多优点,类型安全的良好优点。我遇到的缺点:

  • 您需要在计算中保存中间值...如秒平方。让这些值成为类型有点毫无意义(seconds^2 显然不像 velocity 那样是类型)。
  • 您需要进行越来越复杂的计算,这将需要越来越多的重载/运算符定义才能实现。

归根结底,对于简单的计算和简单的目的来说,它非常干净。但是当数学变得复杂时,很难让一个打字的单位系统发挥得很好。

每个人都提到类型安全保证是一个加号。 另一个巨大的优点是能够从单位(米)中抽象出概念(长度)。

因此,例如,处理单位时的一个常见问题是将 SI 与公制混合使用。 当概念被抽象为类时,这不再是问题:

Length width = Length::fromMeters(2.0);
Length height = Length::fromFeet(6.5);
Area area = width * height; //Area is computed correctly!
cout << "The total area is " << area.toInches() << " inches squared.";

类的用户不需要知道内部表示使用什么单位...至少,只要没有严重的四舍五入问题。


我真的希望更多的三角函数库用角度来做到这一点,因为我总是要查找它们是否期望度数或弧度......

对于那些寻找强大的编译时类型安全单元库,但对拖入 boost 依赖项犹豫不决的人,请查看单元。该库作为单个 .h 文件实现,没有依赖项,并附带一个用于构建单元测试/文档的项目。它使用 msvc2013、2015 和 gcc-4.9.2 进行了测试,并且应该也适用于这些编译器的更高版本。

完全披露:我是图书馆的作者

是的,这是有道理的。不仅在物理学中,而且在任何学科中。例如,在金融领域,利率以反转时间间隔为单位(通常每年表示)。货币有许多不同的单位。它们之间的转换只能通过交叉汇率完成,具有一种货币除以另一种货币的维度。利息支付、股息支付、本金支付等通常以一定频率发生。

它可以防止将两个值相乘并最终得到非法值。它可以防止美元和欧元等的总和。

我并不是说你这样做是错的,但我们在我正在从事的项目中过火了,坦率地说,我怀疑它的好处超过了它的麻烦。特别是如果你在一个团队中,良好的变量命名(只是把的东西拼出来),代码审查和单元测试将防止任何问题。另一方面,如果你可以使用 Boost,单位可能是可以检查的东西(我没有)。

要检查类型安全性,可以使用专用库。

最巧妙的用途是 boost::units,它可以正常工作,没有执行时间开销,有很多功能。如果这个库理论上解决了你的问题。从更实用的角度来看,界面非常笨拙且文档记录不佳,您可能会遇到问题。此外,编译时间会随着维度数量的增加而急剧增加,因此在使用之前,请清楚地检查您是否可以在合理的时间内编译大型项目。

文档 : http://www.boost.org/doc/libs/1_56_0/doc/html/boost_units.html

另一种方法是使用unit_lite。功能比 boost 库少,但编译速度更快,界面更简单,错误消息可读。此库需要 C++11。

代码 : https://github.com/pierreblavy2/unit_lite

文档的链接在 github 描述中(我不允许在这里发布超过 2 个链接!!)。

>我在CPPcon 2015上做了一个关于Boost.Units库的教程演示。这是一个强大的库,每个科学应用程序都应该使用。 但由于文档不佳,它很难使用。 希望我的教程对此有所帮助。 你可以在这里找到幻灯片/代码:

如果你想

使用一个基于 c++20 的非常轻量级的仅标头库,你可以使用 TU(类型安全单位)。它支持对所有 SI 单位进行操作(*、/、+、-、sqrt、pow 到任意浮点数、标量单位上的一元运算)。它支持具有浮点维度的单位,如 length^(d),其中 d 是十进制数。此外,定义自己的单位很简单。它还带有一个测试套件...

。是的,我是这个图书馆的作者。