Как мне конвертировать double или float (все цифры) в int? - PullRequest
2 голосов
/ 06 марта 2019

Как мне преобразовать double или float (все цифры) в int?

Например, если у меня двойное 0,9332, функция вернет 9332, 1,32001 вернет 132001

Ответы [ 5 ]

0 голосов
/ 08 марта 2019

Как конвертировать double или float (все цифры) в int?

0.9332  --> 9332  
1.32001 --> 132001

Цель не всегда возможна в общем.
Обычно , существует около 2 64 разных double. 0.9332 и 1.32001 не входят в этот набор double.


Давайте посмотрим на ближайшие альтернативы.

Ближайшие double имеют точные значения, более похожие на приведенные ниже. Некоторым double, как двоичным значениям с плавающей запятой, требуется 100 с десятичных цифр для точного представления.

0.933200000000000029487523534...
1.32000999999999990563992469...

Для разумного вывода этих значений "в int" нам нужно выбрать желаемую точность.

Допустим, мы выбрали фиксированное количество цифр после десятичной точки. (Не очень хорошая идея для небольших значений double, поскольку все они становятся "0" `), код может постобработать строку по желанию.

int len = snprintf(NULL, n, "%.*f", 16, double_value);
char buf(len + 1];
snprintf(buf, sizeof buf, "%.*f", 16, double_value);
char *dp = strchr(buf, '.');  // Look for the decimal point - might be `,` in some locales
if (dp) {
  size_t len = strlen(dp + 1);
  memmove(dp, dp + 1, len + 1); // shove over fraction
  while (len > 0 && dp[len - 1] == '0') {
    dp[--len] = '\0';  // lop off trailing zeros.
  }
} 

Теперь buf[] содержит только цифры (кроме бесконечности / NaN), подходящие для strto...() преобразования в некоторый целочисленный тип - если он "подходит". buf[] может содержать сотни цифр, так как DBL_MAX часто составляет около 3.0e308 или около того. Цель ОП не выражена для очень больших / маленьких double.


Для ограниченного диапазона double используйте кодовый код "%.*g", который «конечные нули удаляются из дробной части результата», а затем post = обработать строку для удаления '.'.

printf("%.16g\n", 0.9332);
printf("%.16g\n", 1.32001);

Выход * * тысяча пятьдесят-один

0.9332
1.32001
0 голосов
/ 06 марта 2019

Вы без нужды загнали себя в угол. Если вам нужны результаты с правильной десятичной плавающей запятой, вы должны использовать десятичные числа с плавающей запятой, такие как dec64 для своих расчетов, вместо того, чтобы пытаться вернуть ошибочный результат обратно в нормальное состояние.

0 голосов
/ 06 марта 2019

Немного подумав, вы не сможете изящно обработать прямое преобразование из double (или float) в целое число путем простых приведений и умножения из-за не совсем точного ограничения чисел с плавающей точкойпредставляющих все значения, приводящие к повторяющимся десятичным точкам и т. д., что приводит к сбою умножения метода дробной части для чисел типа 9.999999.

Однако вы можете использовать промежуточный string и анализироватьцифры от строки, чтобы избежать всех ловушек.(либо путем преобразования числа в stringstream, если число с плавающей точкой уже находится в вашей программе, либо просто путем чтения значения с плавающей точкой как string для начала.

Тогда этопросто вопрос обработки случаев для отрицательного значения или значений, начинающихся с начальных нулей (например, -31.3333) и затем копирующих (.push_back()) цифры из исходного значения с плавающей запятой в промежуточную строку перед вызовом преобразования в.stoi(), .stol(), or .stoll(). Вы можете использовать обработку исключений try {...} catch {...} для обработки любого неудачного преобразования.

Для вашей функции, возвращающей значение long long, вы можете сделать что-то вроде:

#define LONGDIGITS 19

long long sdigits (std::string s)
{
    int start = 0;                          /* flag skip leading 0 */
    size_t n = 0, maxdigits = LONGDIGITS;   /* set max digits */
    long long l = 0;                        /* int to hold conversion */
    std::string result;                     /* string to hold digits */

    if (s[0] == '-') {              /* if leading '-' */
        result.push_back ('-');     /* save for sign */
        maxdigits++;                /* increment max by 1 */
    }
    for (auto c : s) {              /* loop over all chars */
        if (isdigit (c)) {          /* if not digit skip */
            if (c != '0')           /* if not 0, the set start flag */
                start = 1;
            if (start) {                /* if start set */
                result.push_back (c);   /* add digit to result */
                n++;                    /* increment digit count */
            }
        }
        if (n == maxdigits)         /* if digit count == max */
            break;                  /* break */
    }
    try {                           /* try conversion to long long */
        l = std::stoll (result);
    }
    catch ( std::exception& e ) {   /* catch/handle exception */
        std::cerr << "error: std::" << e.what() << " out_of_range.\n";
    }

    return l;   /* return long long value, or 0 on error */
}

Собрав это вместе в кратком примере, вы можете сделать:

#include <iostream>
#include <string>
#include <limits>
#include <cctype>

#define LONGDIGITS 19

long long sdigits (std::string s)
{
    int start = 0;                          /* flag skip leading 0 */
    size_t n = 0, maxdigits = LONGDIGITS;   /* set max digits */
    long long l = 0;                        /* int to hold conversion */
    std::string result;                     /* string to hold digits */

    if (s[0] == '-') {              /* if leading '-' */
        result.push_back ('-');     /* save for sign */
        maxdigits++;                /* increment max by 1 */
    }
    for (auto c : s) {              /* loop over all chars */
        if (isdigit (c)) {          /* if not digit skip */
            if (c != '0')           /* if not 0, the set start flag */
                start = 1;
            if (start) {                /* if start set */
                result.push_back (c);   /* add digit to result */
                n++;                    /* increment digit count */
            }
        }
        if (n == maxdigits)         /* if digit count == max */
            break;                  /* break */
    }
    try {                           /* try conversion to long long */
        l = std::stoll (result);
    }
    catch ( std::exception& e ) {   /* catch/handle exception */
        std::cerr << "error: std::" << e.what() << " out_of_range.\n";
    }

    return l;   /* return long long value, or 0 on error */
}

int main (void) {

    std::string s;
    long long l;

    std::cout << "enter double in range of 64-bit int: ";
    if (!(std::cin >> s)) {
        std::cerr << "err: invalid input.\n";
        return 1;
    }

    l = sdigits (s);

    std::cout << s << " -> " << l << '\n';
}

Вероятно, есть несколько способов сделать это, поэтому не принимайте это как единственный подход, но вы можете точно обрабатывать преобразованияи подтвердите, чтобы идентифицировать любые сбои.

Пример Использование / Вывод

$ ./bin/double_all_digits
enter double in range of 64-bit int: 0.9332
0.9332 -> 9332

$ ./bin/double_all_digits
enter double in range of 64-bit int: 1.32001
1.32001 -> 132001

Отрицательные значения также обрабатываются правильно:

$ ./bin/double_all_digits
enter double in range of 64-bit int: -0.9332
-0.9332 -> -9332

Используя строку для промежуточного анализа, вы избегаете повторяющихся десятичных чисел с плавающей запятой:

$ ./bin/double_all_digits
enter double in range of 64-bit int: 9.999999
9.999999 -> 9999999

$ ./bin/double_all_digits
enter double in range of 64-bit int: -31.3333
-31.3333 -> -313333

Используя обработку исключений try {...} catch {...}, вы можете поймать любое out_of_range преобразования.Наибольшее допустимое преобразование в long long будет:

$ ./bin/double_all_digits
enter double in range of 64-bit int: 0.9223372036854775807
0.9223372036854775807 -> 9223372036854775807

. При добавлении одного из них значение выходит за пределы диапазона для long long:

$./bin/double_all_digits
enter double in range of 64-bit int: 0.9223372036854775808
error: std::stoll out_of_range.
0.9223372036854775808 -> 0
0 голосов
/ 06 марта 2019

Вы можете использовать стандартную библиотечную строковую функцию C ++ для преобразования числа с плавающей точкой в ​​целое число.

#include <iostream>
#include <string>
#include <cctype>

int floatDigitToInt(float num) {
    std::string str_f = std::to_string(num);
    // here one can check NaN, inf etc..
    std::string str_i;
    for (int i = 0; i < str_f.length(); ++i) {
        if (std::isdigit(str_f[i])) {
            str_i += str_f[i];
        }
    }
    return std::stoi(str_i);
}

int main() {
    float num_f = 1.32001;
    std::cout << floatDigitToInt(num_f);
    return 0;
}
0 голосов
/ 06 марта 2019
this will work ! question is similar to this one :
/4749427/kak-uznat-dlinu-drobnoi-chasti-chisla

#include <iostream>
#include <math.h>
using namespace std;
int getFractionDigitsCount(float );
int main()
{
    float a=1.9332;
    int p = getFractionDigitsCount(a);
    cout<<"answer is : "<< a * pow(10,p);

    return 0;
}
 int getFractionDigitsCount(float d) {
    if (d >= 1) { //we only need the fraction digits
        d = d - (long) d;
    }
    if (d == 0) { //nothing to count
        return 0;
    }
    d *= 10; //shifts 1 digit to left
    int count = 1;
    while (d - (long) d != 0) { //keeps shifting until there are no more fractions
        d *= 10;
        count++;
    }
    return count;
}
...