У меня проблема с переполнением с плавающей точкой - PullRequest
4 голосов
/ 02 ноября 2009

Ну, я новичок, это мой год по специальности компьютерные науки. Я пытаюсь сделать упражнение из моего учебника, в котором я использую структуру под названием 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.

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

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

Ответы [ 6 ]

8 голосов
/ 02 ноября 2009

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

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 не инициализируются при использовании вышеуказанного конструктора.

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

3 голосов
/ 02 ноября 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).

2 голосов
/ 02 ноября 2009

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

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

1 голос
/ 02 ноября 2009

Ваш вывод не соответствует коду, который вы показываете - вы пропустили '<< endl' после времени выполнения, которое, как заявляет ваш вывод, вы включили. Это всегда усложняет отладку. </p>

Вот ваш код, работающий корректно на 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', которое происходит в вызовах конструктора, но, признаюсь, я не понимаю, как это могло случается.

1 голос
/ 02 ноября 2009

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

void displayMovieData(MovieData m)

с

void displayMovieData(const MovieData &m)

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

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

0 голосов
/ 02 ноября 2009

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

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

...