如何在c++中获取双精度值中的位数

How to get the number of digit in double value in C++?

本文关键字:双精度 获取 c++      更新时间:2023-10-16

我试图从双值中获得数字的数量,但它不能正常工作。我试过了:

int main()
{
    double value = 123456.05;
    std::cout<<"number of digit::"<<((int)std::log10(value ) + 1);
}

输出::

位数::6

如何得到确切的数字数?

假设您只需要此操作用于双字面值,则以下操作即可。

编辑:添加了一个等效函数,适用于double类型的子集。它使用穷举搜索所有合理的方式来显示十进制的双精度,如果您需要这个函数真正尖叫,可能有一些方法可以使它更有效。

    #include <iostream>
    #include <string.h>
    #include <assert.h>
    #include <cmath>
    struct double_literal {
            const char* string_value;
            double double_value;
            size_t num_digits;
    };
    #define DOUBLE_LITERAL(x) {#x, x, strlen(#x)};
size_t num_digits(double value){
        //Double gives around 15 accurate digits usually.
        //Disregarding exponential notation, there are hence only 15 reasonable
        //ways to display value, ranging from 15 places in front of the decimal
        //to 15 behind. Figure out which of these is best in terms of error,
        //and then at the end print out how many digits are needed to display
        //the number by removing unecessary zeros.
        //Routine currently only handles values within these bounds
        //If your value is outside, can scale it with a power of ten before
        //using. Special cases for zero and negative values can also be added.
        double window_stop = std::pow(10.0, 15);
        double window_start = 1 + std::pow(10.0, -15);
        assert(value < window_stop);
        assert(value > window_start);
        size_t best_window = 0;
        double best_error = INFINITY;
        double pow_ten_window = 1;
        for(size_t window = 0; window <= 15; window++, pow_ten_window *= 10){
               double rounded = fmod(
                    std::round(value * pow_ten_window),
                    window_stop
               ) / pow_ten_window;
               double error = std::abs(rounded - value);
               if (error < best_error){
                    best_error = error;
                    best_window = window;
               }
        }
        unsigned long long best_rounding = std::llround(
                fmod(
                        value * std::pow(10.0, best_window),
                        window_stop
                )
        );
        size_t best_digits = std::llround(std::log10(best_rounding) + 1);
        //Representation has an integer part => just figure out if we
        //need a decimal point
        if (best_window > 0){
                best_digits++;
        }
        std::cout << best_window << std::endl;
        return best_digits;
}
int main(int argc, char** argv){
        struct double_literal literal DOUBLE_LITERAL(123456.05);
        std::cout << "number of digit::" << literal.num_digits << std::endl;
        //As a function
        std::cout << "numbr of digit::" << num_digits(literal.double_value);
    }

使用文字,您可以在后面的代码中以多种形式获得文字的值。

该函数也适用于非字面量,但仅适用于双精度数的有限子集。请参阅评论,了解如何将其推广到其他部分。

可以将双精度值转换为字符串:

double value = 123456.05;
std::string s = std::to_string(value);

之后,您需要删除尾随零(因为s == "123456.050000"现在可能):

s.erase(s.find_last_not_of('0') + 1, std::string::npos);

则获取该字符串的若干个字符:

std::cout<<"number of digit::"<< s.length();

(在本例中,您将把"。"作为数字处理)

因此,下面的程序返回预期的结果:

位数::9

但是这对于整数值并不完美,因为"123"将被表示为"123"。(最后再加一个字符)。因此,对于整数值,最好在获得长度为

之前删除后面的"。"
void print_nb_digits(double value) {
  std::string s = std::to_string(value);
  s.erase(s.find_last_not_of('0') + 1, std::string::npos);
  if (!s.empty() && !std::isdigit(s.back()))
    s.pop_back();
  std::cout<<"number of digit::"<< s.length();
}
double value = 123456.05;
print_nb_digits(value);

在这种情况下,程序也返回value = 123456的正确结果:

位数::6