【问题标题】:C++ Checking if a double is an integer does not work in some casesC++ 检查双精度是否为整数在某些情况下不起作用
【发布时间】:2023-03-22 08:13:01
【问题描述】:

我正在尝试打印出遵循特定规则的前几个数字:可以将其数字的总和提高到整数幂以得到数字本身。 (基本上,如果总和是数字的 n 次方根)。

例如,数字81中的数字和是9,9^2是81。

这是我正在使用的一些代码:

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <math.h>
using namespace std;

int sumOfDigits(int num) {
    int sum = 0;
    string numStr = "";
    stringstream s;
    s << num;
    s >> numStr;
    for (int i = 0; i < numStr.length(); i++) {
        int ad = 0;
        stringstream ss;
        ss << numStr[i]; // take each digit
        ss >> ad;
        sum += ad; // and add to sum
    }
    return sum;
}

int num = 10; // starting number
int numFound = 0; // how many such special numbers have been found

int main() {
    while (numFound < 5) {
        int sum = sumOfDigits(num);
        double exp = log10(num) / log10(sum);

        if (fmod(exp, 1.0) == 0.0 && sum != 1) { // if the exponent is an integer
            cout << num << "\t" << sum << endl; // then print out the number and the sum of its digits
            numFound++;
        }
        num++;
    }

    return 0;
}

当我运行它时,我得到以下输出:

81      9
2401    7
4913    17
5832    18
17576   26

第二个条目应该是5128,因为 8^3 是 512。我不明白为什么测试适用于某些数字但不适用于其他数字。

我也尝试过其他方法来测试指数是否为整数。我已经针对floor() 表达式对其进行了测试,并尝试使用(int) 转换整个表达式。

我可能错了,问题可能不在那个地方,但如果你能帮助我,我将不胜感激。谢谢。

【问题讨论】:

  • log10(num) / log10(sum) => log(num) / log(sum) 会更快,因为任何碱基的对数都将在内部基于自然对数计算
  • 处理整数时,最好保持在整数域内,而不是转换为浮点数。舍入错误可能会很痛苦。在这种情况下,需要使用不同的算法。

标签: c++ integer double


【解决方案1】:

像这样检查浮点数之间的相等性:fmod(exp, 1.0) == 0.0 一定会给您带来麻烦。例如,只需像这样更改您的代码:

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <math.h>
#include <limits>
using namespace std;

int sumOfDigits(int num) {
    int sum = 0;
    string numStr = "";
    stringstream s;
    s << num;
    s >> numStr;
    for (int i = 0; i < numStr.length(); i++) {
        int ad = 0;
        stringstream ss;
        ss << numStr[i]; // take each digit
        ss >> ad;
        sum += ad; // and add to sum
    }
    return sum;
}

int num = 10; // starting number
int numFound = 0; // how many such special numbers have been found

int main() {
    while (numFound < 5) {
        int sum = sumOfDigits(num);
        double exp = log10(num) / log10(sum);

        if (fabs(fmod(exp, 1.0)) < std::numeric_limits<float>::epsilon() && sum != 1) { // if the exponent is an integer
            //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            cout << num << "\t" << sum << endl; // then print out the number and the sum of its digits
            numFound++;
        }
        num++;
    }

    return 0;
}

我可以得到这个输出:

81  9
512 8
2401    7
4913    17
5832    18

因此,请使用合适的 epsilon 值或只使用整数。

在这里阅读:

What is the most effective way for float and double comparison?

【讨论】:

  • 当我运行它时,它会在 if 语句中抛出一个错误:invalid operands to binary expression ('double' and 'type (*)() throw()' (aka 'float (*)() throw()')) if (fabs(fmod(exp, 1.0)) &lt; std::numeric_limits&lt;float&gt;::epsilon &amp;... 我该怎么做才能解决这个问题?抱歉,我对 c++ 有点陌生。
  • @Beöbe :编辑了代码。在 epsilon 之后缺少括号。
【解决方案2】:

循环总和和指数会快得多:

unsigned int number;
unsigned int min_sum =   3;
unsigned int max_sum = 100;
unsigned int min_exp =   2;
unsigned int max_exp =  20;

int main() {
    for (unsigned int exp = min_exp; exp <= max_exp; ++exp) 
        for (unsigned int sum = min_sum; sum <= max_sum; ++sum) {
            number = pow(sum, exp);
            if ( sumOfDigits(number) == sum ) 
                cout << numFound++ << ":\t" << number << "\t = " << sum << " ^ \t" << exp << endl;
        }
    return 0;
}

【讨论】:

  • 这是一个有趣的方法。肯定会快很多。感谢您提及!
猜你喜欢
  • 2019-07-12
  • 2015-04-11
  • 1970-01-01
  • 2011-06-26
  • 2018-11-28
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多