У меня проблема с переполнением с плавающей запятой

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

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

// struct called MovieData
struct MovieData
{
    string title;
    string director;
    unsigned year;
    unsigned running_time;
    double production_cost;
    double first_year_revenue;

    MovieData() // default constructor
    {
        title = "Title";
        director = "Director";
        year = 2009;
        running_time = 90;
        production_cost = 1000000.00;
        first_year_revenue = 1000000.00;
    }
    // Constructor with arguments:
    MovieData(string t, string d, unsigned y, unsigned r, double p, double f)
    {
        title = t;
        director = d;
        year = y;
        running_time = r;
    }
};

// function prototype:
void displayMovieData(MovieData);

// main:
int main()
{
    // declare variables:
    MovieData movie, terminator("Terminator", "James Cameron", 1984, 120, 5000000, 2000000);

    // calling displayMovieData function for movie and terminator
    // so it will display information about the movie:
    displayMovieData(movie);
    displayMovieData(terminator);

    return 0;
}

// displayMovieData function:
// It receives struct MovieData variable as
// an argument and displays that argument's
// movie information to the user.
void displayMovieData(MovieData m)
{
    cout << m.title << endl;
    cout << m.director << endl;
    cout << m.year << endl;
    cout << m.running_time << endl;
    cout << fixed << showpoint << setprecision(2);
    cout << m.production_cost << endl;
    cout << m.first_year_revenue << endl << endl;
}

вот результат, который я получил:

Title
Director
2009
90
1000000.00
1000000.00

Terminator
James Cameron
1984
120
-92559631349317830000000000000000000000000000000000000000000000.00
-92559631349317830000000000000000000000000000000000000000000000.00

Press any key to continue . . .

Скомпилировано на Microsoft Visual C ++ 2008 Express Edition.

Мой вопрос: происходит ли это из-за переполнения типа данных double? Я даже пробовал использовать long double, и происходит то же самое. хотя я использовал 5мил как production_cost и 2мил как first_year_revenue, оба числа выводятся одинаково. При правильном использовании конструктора по умолчанию выводится 1000000. Правильный ли тип данных я использую в этом случае? Я хочу, чтобы оно было вдвое больше, потому что это денежное число в долларах и центах.

Спасибо за любую помощь. Извините за мой длинный вопрос. Это мой первый пост на SO, так что любые отзывы о правильном формате размещения вопросов будут отличными, спасибо!


person Community    schedule 02.11.2009    source источник
comment
вы можете предоставить функцию displayMovieData? Я думаю, что двойное переполнение на 2 мил маловероятно.   -  person Oren Mazor    schedule 02.11.2009
comment
вы можете опубликовать содержимое функции displayMovieData ()?   -  person Andrew Keith    schedule 02.11.2009
comment
Выложил содержимое функции и весь код программы.   -  person    schedule 02.11.2009
comment
Использование чисел с плавающей запятой / удвоением для денег - не лучшая идея, особенно если вы планируете делать с ними математику. Вы должны использовать типы данных на основе int, а затем просто отформатировать строку с десятичным разрядом, когда вам нужно ее распечатать.   -  person Jim Buck    schedule 02.11.2009
comment
В пересмотренном коде вы не инициализируете поля production_cost или first_year_revenue.   -  person Jonathan Leffler    schedule 02.11.2009
comment
Урок отладки состоит в том, что никогда не следует ничего предполагать. Измените одну вещь за раз, сужайте ее до тех пор, пока вы не исключите возможности с абсолютной уверенностью. Не потому, что я знаю, что этого не могло быть. но знайте, что этого не может быть, потому что вы вставили операторы печати или что-то еще и протестировали.   -  person Omnifarious    schedule 02.11.2009
comment
Тем не менее, догадки по-прежнему хороши. После того, как вы натренируете свою интуицию, они будут правы достаточно часто, чтобы сэкономить много времени. Мой предел - 2 или 3 догадки, прежде чем я сдамся и начну полностью систематически работать над этим.   -  person Omnifarious    schedule 02.11.2009


Ответы (6)


Спасибо, что разместили полный код, проблема очевидна. Следующая функция является проблемой:

MovieData(string t, string d, unsigned y, unsigned r, double p, double f)
{
    title = t;
    director = d;
    year = y;
    running_time = r;
}

Вы пропустили следующие утверждения:

    production_cost = p;
    first_year_revenue = f;

Без этих операторов production_cost и first_year_revenue не инициализируются при использовании вышеуказанного конструктора.

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

person Greg Hewgill    schedule 02.11.2009
comment
Ого, спасибо. Я чувствую себя очень маленьким после этой ошибки. Я смотрел на него, смотрел на него, он был прямо передо мной, но я его не видел. Спасибо за помощь! - person ; 02.11.2009

Исправляя ошибки, мешавшие компиляции кода (отсутствие точек с запятой, прописная M вместо строчной m), я получаю следующее:

#include <iostream>
#include <iomanip>

using namespace std;

struct MovieData
{
    string title;
    string director;
    unsigned year;
    unsigned running_time;
    double production_cost;
    double first_year_revenue;

    MovieData() // My default constructor
    {
        title = "Title";
        director = "Director";
        year = 2009;
        running_time = 90;
        production_cost = 1000000.00; // this one comes out ok.
        first_year_revenue = 1000000.00; // this one comes out ok as well.
    }
    // This is my constructor with arguments:
    MovieData(string t, string d, unsigned y, unsigned r, double p, double f)
    {
        title = t;
        director = d;
        year = y;
        running_time = r;
        production_cost = p;
        first_year_revenue = f;
    }
};

void displayMovieData(MovieData m)
{
    cout << m.title << endl;
    cout << m.director << endl;
    cout << m.year << endl;
    cout << m.running_time;
    cout << fixed << showpoint << setprecision(2);
    cout << m.production_cost << endl;
    cout << m.first_year_revenue << endl << endl;
}

int main()
{
  MovieData terminator(
    "Terminator", "James Cameron", 1984, 120, 5000000, 2000000);
  displayMovieData(terminator);
  return 0;
}

Его компиляция и запуск не воспроизводят вашу проблему ...:

$ g++ -Wall --pedantic z.cc
$ ./a.out
Terminator
James Cameron
1984
1205000000.00
2000000.00

$ 

Скопируйте и вставьте код точно так, как я дал его здесь, и сообщите нам, что происходит (и с каким компилятором, платформой и т. Д. И т. Д. - я использую gcc 4.0.1 на MacOSX 10.5).

person Alex Martelli    schedule 02.11.2009
comment
Может быть, добавить недостающий endl для ясности. - person Greg Hewgill; 02.11.2009
comment
Это два Mac, которые дают один и тот же ответ :) - person Jonathan Leffler; 02.11.2009

Нет, вы никогда не собираетесь выходить за рамки двойника доходами или производственными затратами любого фильма.

Я предполагаю, что проблема заключается в вашей функции displayMovieData. Можете ли вы опубликовать код для этого?
IIRC вы можете получить такие странные значения, если вы вызовете что-то вроде printf, и он перепутается между одиночными и двойными. Или если вы передадите %d вместо _2 _...

person Peter    schedule 02.11.2009
comment
IEEE754 Double - подходит для верхнего предела ~ 1,79x (10 ^ 308) - с уменьшающейся точностью, конечно - person ; 02.11.2009
comment
Ага. Даже Waterworld стоил не так уж и дорого :) - person Peter; 02.11.2009
comment
Я не знал подробностей, просто ввел цифры. Возможно, создание фильма не так дорого стоило, но, чтобы удовлетворить свое любопытство, я хотел бы знать, как я могу использовать большие суммы в качестве чисел с плавающей запятой для своего собственного образования, и на случай, если я когда-нибудь столкнусь с чем-то вроде это снова. - person ; 02.11.2009
comment
У меня нет проблем с числами, которые вы вводите. Я просто не думаю, что проблема здесь в переполнении - как уже упоминалось в pst, максимальное значение double огромно. - person Peter; 02.11.2009

Ваш вывод не соответствует коду, который вы показываете - вы пропустили '‹* endl' после времени выполнения, которое вы указали в вашем выводе. Это всегда усложняет отладку.

Вот ваш код, корректно работающий в MacOS X 10.5.8 (Leopard) с G ++ 4.0.1.

#include <string>
using namespace std;

struct MovieData
{
    string title;
    string director;
    unsigned year;
    unsigned running_time;
    double production_cost;
    double first_year_revenue;

    MovieData() // My default constructor
    {
        title = "Title";
        director = "Director";
        year = 2009;
        running_time = 90;
        production_cost = 1000000.00; // this one comes out ok.
        first_year_revenue = 1000000.00; // this one comes out ok as well.
    }
    // This is my constructor with arguments:
    MovieData(string t, string d, unsigned y, unsigned r, double p, double f)
    {
        title = t;
        director = d;
        year = y;
        running_time = r;
        production_cost = p;
        first_year_revenue = f;
    }
};

#include <iostream>
#include <iomanip>
using namespace std;

void displayMovieData(MovieData m)
{
    cout << m.title << endl;
    cout << m.director << endl;
    cout << m.year << endl;
    cout << m.running_time << endl;
    cout << fixed << showpoint << setprecision(2);
    cout << m.production_cost << endl;
    cout << m.first_year_revenue << endl << endl;
}

int main()
{
    MovieData def;
    MovieData terminator("Terminator", "James Cameron", 1984, 120, 5000000, 2000000);
    MovieData terminator2("Terminator 2", "James Cameron", 1984, 120, 5000000.0, 2000000.0);
    displayMovieData(def);
    displayMovieData(terminator);
    displayMovieData(terminator2);
}

Я получаю следующий результат:

Title
Director
2009
90
1000000.00
1000000.00

Terminator
James Cameron
1984
120
5000000.00
2000000.00

Terminator 2
James Cameron
1984
120
5000000.00
2000000.00

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

person Jonathan Leffler    schedule 02.11.2009
comment
На этот раз я добавил весь код как один блок, а результаты - как единое целое. - person ; 02.11.2009

Как и другие ответы здесь, я не уверен, в чем может быть проблема, поскольку с кодом все в порядке. Однако попробуйте заменить это объявление:

void displayMovieData(MovieData m)

с участием

void displayMovieData(const MovieData &m)

и посмотрите, улучшится ли ваша ситуация. См. Недавний вопрос Почему предпочтительно писать func ( const Class & value)? для получения дополнительной информации о различиях между этими двумя объявлениями.

Я должен подчеркнуть, что это не должно не изменять поведение вашей программы, но если что-то в вашем компиляторе и / или среде выполнения содержит ошибку, указанное выше изменение кода может помочь изолировать проблему.

person Greg Hewgill    schedule 02.11.2009
comment
Я попробовал ваше предложение, и это не имело значения. Спасибо за лакомый кусочек. - person ; 02.11.2009

Я бы попробовал прибавить 0,0 к числу и сделать их удвоенными. Может возникнуть путаница при попытке выполнить перевод из целого числа в двойное.

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

person Glenn    schedule 02.11.2009