Почему этот код получает исключение с плавающей запятой, когда нет типа данных с плавающей запятой?

Я не делю на ноль, и в моем коде нет типа данных с плавающей запятой, я все еще получаю исключение с плавающей запятой.

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
    unsigned long long int t,n;

    cin>>t;
    while(t--)
    {
        cin>>n;
        unsigned long long int deno = pow(10,n-1),count=2,sum = 0,f1=1,f2=1;

         while(1){
            sum = f1+f2;
            f1 = f2;
            f2 = sum;
            count++;
            if((int)(sum/deno)>0){
                cout<<count<<endl;
                 break;
             } 
        }

    }
    return 0;
}

Все предыдущие вопросы об одном и том же имели аналогичную проблему деления на ноль, но переменная deno никогда не может быть равна нулю, как n>=2.

Предыдущие исследования с моей стороны:

  1. "Исключение с плавающей запятой" в коде, не содержащем float< /а>
  2. Исключение с плавающей запятой С++ Почему и что это такое?

Постановка задачи: https://www.hackerrank.com/contests/projecteuler/challenges/euler025/problem

Он проходит 2 тестовых случая и терпит неудачу 2. Все тестовые случаи являются скрытыми. Изображение результата

При передаче ввода 1 50 мы можем воспроизвести ошибку. Подробности:

 GDB trace: Reading symbols from solution...done. [New LWP 15127] Core
 was generated by `solution'. Program terminated with signal SIGFPE,
 Arithmetic exception.
 #0  main () at solution.cc:23 
 23 if((int)(sum/deno)>0){
 #0  main () at solution.cc:23

person Breakpoint    schedule 11.07.2018    source источник
comment
Исключение с плавающей запятой - это когда вы пытаетесь выполнить деление или деление по модулю на 0. оно не является исключительным для плавающих точек   -  person Tyker    schedule 12.07.2018
comment
Сколько времени нужно, чтобы воспроизвести проблему? Когда я запускаю ваш код, он просто продолжает работать.   -  person merlin2011    schedule 12.07.2018
comment
Используйте свой отладчик. Наблюдайте за значением deno и смотрите, равно ли оно нулю.   -  person alter igel    schedule 12.07.2018
comment
@merlin2011 Он отлично работает на hackerrank.com. Пройденные тесты заняли меньше секунды.   -  person Breakpoint    schedule 12.07.2018
comment
Какие значения вы вводите? я не получаю ошибку   -  person Easton Bornemeier    schedule 12.07.2018
comment
@Easton Bornemeier скрытый тестовый пример! Это отлично работает для 2 тестовых случаев, но создает исключение с плавающей запятой для остальных двух   -  person Breakpoint    schedule 12.07.2018
comment
@TotallyNoob, в этом случае было бы полезно предоставить ссылку на исходную проблему.   -  person merlin2011    schedule 12.07.2018
comment
hackerrank.com/contests/projecteuler/challenges/euler025/   -  person Breakpoint    schedule 12.07.2018
comment
Я не смог отредактировать вопрос, это постановка проблемы   -  person Breakpoint    schedule 12.07.2018
comment
Ваш код кажется полностью работоспособным без исключения. Вы отлаживали свой код шаг за шагом?   -  person Yılmaz edis    schedule 12.07.2018
comment
Отладка @Yilmazedis не поможет, если вы не знаете входных данных, которые приводят к проблеме.   -  person bolov    schedule 12.07.2018
comment
@ scohe001 Даже после C++98 std::pow() работает только с числами с плавающей запятой.   -  person BessieTheCookie    schedule 12.07.2018
comment
@Yılmazedis Да, я пытался напечатать значения deno, и, насколько я могу думать, deno никогда не становилось равным нулю, поэтому исключение с плавающей запятой в этом случае немного сбивает с толку.   -  person Breakpoint    schedule 12.07.2018
comment
@FeiXiang Ааа, присмотревшись к (7), кажется, ты прав. Я бегло просмотрел и не слишком внимательно посмотрел на то, что Arithmetic1 думал, что он справится с int   -  person scohe001    schedule 12.07.2018
comment
случай ввода для исключения с плавающей запятой: 1 50   -  person bolov    schedule 12.07.2018
comment
@bolov Да, ты прав.   -  person Yılmaz edis    schedule 12.07.2018
comment
@болов спасибо! Я отредактировал вопрос и поместил сообщение об ошибке для лучшего понимания   -  person Breakpoint    schedule 12.07.2018
comment
Вы понимаете, что unsigned long long может состоять только из 19 цифр, а задача требует 5000? Даже long double может содержать только до 308 цифр (конечно, с ошибкой с плавающей запятой). Вам понадобится новый подход.   -  person BessieTheCookie    schedule 12.07.2018
comment
Это просто вызывает переполнение   -  person Easton Bornemeier    schedule 12.07.2018
comment
@FeiXiang Большое спасибо! Я собираюсь изменить подход.   -  person Breakpoint    schedule 12.07.2018
comment
Стандартом де-факто является gmplib.org.   -  person o11c    schedule 12.07.2018


Ответы (1)


Для целочисленного деления совершенно нормально создавать исключение, которое сообщается как «исключение с плавающей запятой» на некоторых платформах (например, Linux). Вы можете легко получить его из целочисленного деления на ноль или, например, путем запуска переполнения, как в

int i = INT_MIN;
int b = -1;
i = i / b;

http://coliru.stacked-crooked.com/a/07c5fdf47278b696

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


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

unsigned long long int deno = pow(10,n-1);

получается ноль в deno. pow — это функция с плавающей запятой, которая выдает результат с плавающей запятой. Преобразование типа с плавающей запятой в целочисленный тип приводит к неопределенному поведению, если исходное значение слишком велико (как в случае n, равного 50). Обратите внимание, что это так, даже если целевой целочисленный тип не имеет знака.

person AnT    schedule 11.07.2018
comment
Спасибо, но как мне изменить свой код, чтобы решить эту проблему? - person Breakpoint; 12.07.2018
comment
Спасибо за глубокое изучение проблемы и помощь - person Breakpoint; 12.07.2018
comment
да, только что проверил, что 1 50 deno равно 0. Однако в Visual Studio это 9223372036854775808. Это действительно УБ. - person bolov; 12.07.2018
comment
Напишите свою собственную функцию pow(). std::pow всегда преобразует целые числа и возвращает результаты с плавающей запятой. Нет эквивалента для целых чисел только в стандартной библиотеке. В Интернете есть множество эквивалентов int. - person doug; 12.07.2018
comment
при n›=19 логика плохо сформирована на широком диапазоне платформ. он просто переполняет 64-битные границы long long. - person Red.Wave; 12.07.2018
comment
Немного похоже: можно использовать алгоритм русского крестьянина:lafstern.org/matt/col3.pdf для эффективного целочисленного возведения в степень. Он основан на древнем подходе уменьшения силы умножения до сложения/вычитания/сравнения. В этом случае он уменьшает силу операции от возведения в степень до умножения. - person Arne Vogel; 16.07.2018