C ++ 11 — Как получить количество цифр в двойном значении в C ++?

Я пытался получить номер цифры из двойного значения, но он не работает должным образом. Я попробовал это:

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

выход::

количество цифр :: 6

Как получить точное количество цифр? Ожидаемый результат 9.

-1

Решение

Предполагая, что это нужно только для работы с двойными литералами, сработает следующее.

РЕДАКТИРОВАТЬ: Добавлена ​​эквивалентная функция, которая работает для подмножества двойников. Он использует исчерпывающий поиск всех разумных способов отображения двойного числа в десятичной дроби, возможно, есть какой-то способ сделать его более эффективным, если вам нужна эта функция, чтобы действительно кричать.

    #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. Смотрите комментарии о том, как обобщить это для остальных.

2

Другие решения

Вы можете преобразовать двойное значение в строку:

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

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector