Немного подумав, вы не сможете изящно обработать прямое преобразование из 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