在 C++ 与 Python 中提升权力
Posted
技术标签:
【中文标题】在 C++ 与 Python 中提升权力【英文标题】:Raising to powers in C++ vs. Python 【发布时间】:2016-04-03 18:52:18 【问题描述】:来自 Python,我注意到 C++ 中的东西往往更复杂一些。一个很好的例子是将数字提升到幂。在 Python 的数学库中,只需要:
a = a**b
但是,在 C++ 中,我在在线文档中找到了解释,例如.....
//float
pow( float base, float exp );
//double
pow( double base, double exp );
//long double
pow( long double base, long double exp );
//float
pow( float base, int iexp );
//double
pow( double base, int iexp );
//long double
pow( long double base, int iexp );
//promoted
pow( Arithmetic1 base, Arithmetic2 exp );
显然,C++ 的创建者一定有充分的理由这样做,但作为一个新程序员,这些理由让我无法理解。这是否为答案提供了更大的灵活性?就权力而言,我在 C++ 中获得了哪些好处?
【问题讨论】:
主要原因是C++是静态类型的,而Python不是。 没那么简单。您从使用角度展示 Python,从声明角度展示 C++。从使用的角度来看,C++ 代码将是a = pow(a,b)
,几乎不比 Python 对应的代码更冗长。 OTOH,从声明的角度来看,Python 中至少有 long.__pow__()
、float.__pow__()
。
@el.pescado,既然你提到了它,我在哪里可以找到 python 内部实现?
【参考方案1】:
您发现的多个声明是 C++ 具有 静态类型 与 Python 的 动态类型 的结果。在 Python 中,当你在一个值上调用一个函数时,它可以在运行时确定你是在一个整数、浮点数还是一些更复杂的对象上调用它,并采取适当的行动。在 C++ 中,您不能使用不同类型调用相同的函数,因此您必须为希望支持的所有类型声明不同版本的函数。然而,与 C 不同的是,您可以拥有具有相同名称但参数签名不同的函数(正如 Untitled123 所指出的,这称为 函数重载)。这实际上使您的生活更轻松,因为您只需调用pow(a,b)
而不必担心为您想要的类型调用哪个特殊函数(例如pow_float_int(a,b)
或pow_float_float(a,b)
),编译器将根据您调用正确的版本根据参数的类型。
【讨论】:
@Untitled123 是的。那是我的观点。我不确定你在说什么,函数重载仍然需要定义多个函数。当我说“你不能用不同的类型调用同一个函数”时,我想我可能会更清楚。 你能删除吗 这实际上让你的生活更轻松,因为你可以只调用 pow(a,b) 而不必担心为你想要的类型调用哪个特殊函数(例如 pow_float_int(a, b) 或 pow_float_float(a,b) 部分,这是非常具有误导性的 detail:这个答案从实现的角度展示了 C++ 在这方面与 python 的不同之处,但即使是重载的函数也可以用运算符的形式表示。例如,考虑 std::ostream 重载 该行的原始版本有一点关于如何调用 pow_float_int ,我没有发现他最初更改了句子的第一部分。 嘿转,感谢您的全面回答。它有很大帮助。很难确定您的答案和 Untitled 的答案哪个更好。【参考方案2】:python 中的数字没有限制。由此产生的一些后果是程序往往更慢,因为 python 不是静态类型的,并且有更多的开销,因为它不知道一个数字是否在某个范围内。简而言之,以这种方式使用重载函数的主要原因是出于速度目的,并且更容易推理引擎盖下发生的事情。 Python 提供了很多便利,但有时会变得很难推理。
其次,大多数语言都有一个 math.pow 函数(例如 Java),虽然有点冗长,但我认为它仍然很容易理解。请注意,当您在 C++ 中调用 pow() 时,编译器会确定应该调用哪个 pow(某种数据类型,某种数据类型),无需担心多个定义。
【讨论】:
“你有相同的战俘” - 垃圾。有几个完全不同的函数具有不同的实现和不同的签名 - 但名称相同。按照惯例(好吧,在pow
的情况下,这是一个标准问题)这些不同的函数都在执行相同的数学运算,并且编译器确实确定要调用哪个函数 -但它不是“相同”的战俘。
是的,编译器通过函数重载来解决这个问题……也许我应该改写一下。我试图强调在最终用户端如何调用相同的 pow 函数。不需要 powForFloats()、powForInts() 等。
您一直在说“相同的 pow 函数”,但我的意思是它绝对是 NOT 相同的 pow 函数。它的名称相同,但功能不同。
对于最终用户,调用 Math.pow 函数。在内部,编译器选择不同的函数。我想强调的部分可能需要更坦率地说出来,虽然 C++ 有多种 power 实现,但您不必担心调用哪一个,因为这是自动计算出来的。
对。这好多了。谢谢!【参考方案3】:
拥有多个函数签名的好处在于编译时优化与运行时决策。
在 Python 中,**
操作在运行时查看其参数并决定应用什么算法。整数指数与有理指数与任意浮点无限精度指数与复数指数与其他任何东西。这个决定需要时间。
在 C++ 中,当编译器看到pow(x, y)
时,它在编译时就知道x
和y
的类型,因此它可以选择最匹配的pow()
。反过来,这允许编译器避免任何类型的运行时决策。根据头文件的编写方式和/或整个程序优化的存在,编译器甚至可以内联调用并避免除了实际计算能力之外的任何类型的运行时开销。
这通常无关紧要。但是,如果您的 pow()
调用处于具有数百万次迭代的紧密循环中,那么它可能很重要。
【讨论】:
如果在 C++ 中有一个操作符来获得权力,它也可以在编译时解析为调用。显然 a**b 无法完成,因为 *b 是 deref 等。但我认为 a^b 可能只要 a、b 之一是浮点数(否则 ^ 是整数之间的异或)。我确实希望 C++ 至少有更好的方法将浮点数提高到小整数幂。 运算符只是语法糖。重要的是 C++ 如何允许这种优化不仅适用于语言结构或标准库,而且适用于任意分配代码。哦,您可以为 float 和 int 定义运算符 ^,尽管这不是一个好主意。 实际上,在 gcc 中,我得到了 float、int 的无效操作数类型。为什么不是个好主意?我承认这只是糖,但它可以很好地翻译来自 Fortran 等的数字代码。 我认为我的想法不仅仅是添加库,而是改变语言。我认为权力不希望任何人能够在基本类型之间铁路运营商。我认为符合标准的编译器都会阻止 a^b ,除非两者都是不可分割的。而且您在任何情况下都不应该覆盖操作员。不过,我仍然认为 a^b 会是一小撮糖。 在 C++ 中查找运算符重载。这是一个坏主意,因为运算符的原始含义会妨碍。【参考方案4】:如你所知,在 c++ 中,我们使用函数代替运算符(如 python)
你可以像上面的例子一样使用 pow。该功能有多种使用模式,每次向其发送不同的变量时,系统都会决定选择哪种模式。 pow( float base, float exp ); 和 pow( double base, double exp ); 不一样,都是独立的函数
现在,当您使用 Python 时,状态完全相同。 ** 运算符就像具有不同模式的 C++ 函数。就像the operators in C++的定义一样
希望你能理解我的提示
【讨论】:
以上是关于在 C++ 与 Python 中提升权力的主要内容,如果未能解决你的问题,请参考以下文章