C++ 使用 *this 属性调用单个辅助函数
C++ calling single helper function with *this attributes
编辑:我是 C++ 的初学者,我想了解更多有关如何优化我的代码的信息。
我在 C++ 中创建了一个 Fraction 对象以及重载的 +, - 操作等。然而,当我谈到一元运算符时,我意识到我不知道如何以最有效的方式减少分数.所以我有一个函数 gcd 可以找到最大的除数:
int gcd (int n, int m) {
int newN = n < 0 ? -n : n;
int newM = m < 0 ? -m : m;
if (newM <= newN && newN % newM == 0) { return newM; }
else if (newN < newM) { return gcd(newM, newN); }
else { return gcd(newM, newN%newM); }
}
然后我有一个重载运算符,例如增量:
Fraction& Fraction::operator++() {
num = num + denom;
//reduce fraction
int divisor = gcd(denom,num);
num = num/divisor;
denom = denom/divisor;
if (num < 0 && denom < 0) {num *= (-1);}
if (denom < 0) {denom *= (-1);}
return *this;
}
为了提高效率,我想将代码的 reduce fraction
部分放在单独的 单个 辅助函数中,因此最终函数如下所示:
Fraction& Fraction::operator++() {
num = num + denom;
//reduce fraction
reduce(num, denom);
return *this;
}
这样我就不必每次重载一元运算符时都复制和粘贴 //reduce fraction
中的任何内容。但是,我不确定 reduce(Fraction num, Fraction& denom) 函数应该是什么样子。最多我可以这样实现:
void reduce(int& num, int& denom) {
int divisor = gcd(denom,num);
num = num/divisor;
denom = denom/divisor;
if (num < 0 && denom < 0) {num *= (-1);}
if (denom < 0) {denom *= (-1);}
}
我确信上面的代码会 运行 在编译过程中出现问题,所以我想知道是否可以向我建议任何关于有效创建 reduce fraction 函数的指示。这可能有点挑剔,因为我的原始代码 运行 很好,但由于我是 C++ 的新手,我想了解更多关于如何使我的代码更高效的信息。非常感谢!如果需要更多信息,请告诉我。
编辑:以上代码无效。编译正确,但不能正确减少分数。所以 1/2 + 1/4 结果是 6/8,而不是 3/4。
好吧,在高层次上,您的 gcd 函数太复杂了,reduce 的最后一部分有点错误。如果只有 denom 为负,则将其反转。
很好地展示了为什么将代码放入适当的函数中总是一个好主意,因为它们也可以单独测试。所以我建议为您的 reduce 和 gcd 函数编写一些单元测试。
从一个简单的解决方案开始,例如
static int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
考虑到 % semantics 并在需要时适应负数。考虑一下这个函数应该已经很好了,你只需要在 reduce.
中调用 std::abs(gcd(n,d))
一般来说,你应该问问自己是否真的要在每一个操作中支付重规范化成本,或者你是否让用户决定何时调用 reduce。
对于较低级别的优化,这里有一些提示:
- 总是test/measure,例如通过查看编译器使用 godbolt.org.
实际生成的内容
- 在这种情况下,从性能的角度来看,gcd 中的递归不是问题,因为它是 tail recursive,编译器会为您将它变成一个循环。
- reduce 中的 out 参数不利于优化,因为编译器必须证明它们不指向同一个对象。如果可能,在调用站点返回 std::pair 并使用 C++11 std::tie 或 C++17 结构化绑定会更优雅。
编辑:我是 C++ 的初学者,我想了解更多有关如何优化我的代码的信息。
我在 C++ 中创建了一个 Fraction 对象以及重载的 +, - 操作等。然而,当我谈到一元运算符时,我意识到我不知道如何以最有效的方式减少分数.所以我有一个函数 gcd 可以找到最大的除数:
int gcd (int n, int m) {
int newN = n < 0 ? -n : n;
int newM = m < 0 ? -m : m;
if (newM <= newN && newN % newM == 0) { return newM; }
else if (newN < newM) { return gcd(newM, newN); }
else { return gcd(newM, newN%newM); }
}
然后我有一个重载运算符,例如增量:
Fraction& Fraction::operator++() {
num = num + denom;
//reduce fraction
int divisor = gcd(denom,num);
num = num/divisor;
denom = denom/divisor;
if (num < 0 && denom < 0) {num *= (-1);}
if (denom < 0) {denom *= (-1);}
return *this;
}
为了提高效率,我想将代码的 reduce fraction
部分放在单独的 单个 辅助函数中,因此最终函数如下所示:
Fraction& Fraction::operator++() {
num = num + denom;
//reduce fraction
reduce(num, denom);
return *this;
}
这样我就不必每次重载一元运算符时都复制和粘贴 //reduce fraction
中的任何内容。但是,我不确定 reduce(Fraction num, Fraction& denom) 函数应该是什么样子。最多我可以这样实现:
void reduce(int& num, int& denom) {
int divisor = gcd(denom,num);
num = num/divisor;
denom = denom/divisor;
if (num < 0 && denom < 0) {num *= (-1);}
if (denom < 0) {denom *= (-1);}
}
我确信上面的代码会 运行 在编译过程中出现问题,所以我想知道是否可以向我建议任何关于有效创建 reduce fraction 函数的指示。这可能有点挑剔,因为我的原始代码 运行 很好,但由于我是 C++ 的新手,我想了解更多关于如何使我的代码更高效的信息。非常感谢!如果需要更多信息,请告诉我。
编辑:以上代码无效。编译正确,但不能正确减少分数。所以 1/2 + 1/4 结果是 6/8,而不是 3/4。
好吧,在高层次上,您的 gcd 函数太复杂了,reduce 的最后一部分有点错误。如果只有 denom 为负,则将其反转。 很好地展示了为什么将代码放入适当的函数中总是一个好主意,因为它们也可以单独测试。所以我建议为您的 reduce 和 gcd 函数编写一些单元测试。 从一个简单的解决方案开始,例如
static int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
考虑到 % semantics 并在需要时适应负数。考虑一下这个函数应该已经很好了,你只需要在 reduce.
中调用 std::abs(gcd(n,d))一般来说,你应该问问自己是否真的要在每一个操作中支付重规范化成本,或者你是否让用户决定何时调用 reduce。
对于较低级别的优化,这里有一些提示:
- 总是test/measure,例如通过查看编译器使用 godbolt.org. 实际生成的内容
- 在这种情况下,从性能的角度来看,gcd 中的递归不是问题,因为它是 tail recursive,编译器会为您将它变成一个循环。
- reduce 中的 out 参数不利于优化,因为编译器必须证明它们不指向同一个对象。如果可能,在调用站点返回 std::pair 并使用 C++11 std::tie 或 C++17 结构化绑定会更优雅。