2016-04-26 3 views
0

Я написал решение проблемы Google Code Jam, как показано:C++ Добавление Не Рабочая

#include <iostream> 
#include <fstream> 
#include <string> 
#include <vector> 
#include <map> 
#include <cmath> 

using namespace std; 

int main(int argc, char** argv) { 
     ifstream in; 
     in.open(argv[1]); 
     int t, c = 0; 
     in >> t; 
     while(c++<t) { 
       string msg; 
       in >> msg; 
       map<char,int> m; 
       int base = 0; 
       for(char& ch : msg) { 
         if(!m[ch]) { 
           base++; 
           m[ch] = base == 1 ? base : (base == 2 ? -1 : base - 1); 
         } 
       } 
       if(base < 2) 
         base = 2; 
       double total = 0; 
       double p = pow(base, msg.size()-1); 
       for(char& ch : msg) { 
         if(m[ch] != -1) { 
           if(c == 37) cout << "total=" << total << "+" << (m[ch] * p) << "=" << total + (m[ch] * p) << endl; 
           total = total + (m[ch] * p); 
         } 
         p /= base; 
       } 
       cout.precision(0); 
       cout << fixed << "Case #" << c << ": " << total << endl; 
     } 
     in.close(); 
     return 0; 
} 

Как вы можете видеть, у меня есть некоторые отладочные быть распечатаны для случая 37, потому что некоторые странные вещи случаются там:

Case #36: 1000000000000000000 
total=0+450283905890997376=450283905890997376 
total=450283905890997376+100063090197999424=550346996088996800 
total=550346996088996800+16677181699666570=567024177788663360 
total=567024177788663360+5559060566555523=572583238355218880 
total=572583238355218880+1853020188851841=574436258544070720 
total=574436258544070720+1235346792567894=575671605336638592 
total=575671605336638592+205891132094649=575877496468733248 
total=575877496468733248+68630377364883=575946126846098112 
total=575946126846098112+22876792454961=575969003638553088 
total=575969003638553088+15251194969974=575984254833523072 
total=575984254833523072+847288609443=575985102122132544 
total=575985102122132544+564859072962=575985666981205504 
total=575985666981205504+62762119218=575985729743324736 
total=575985729743324736+20920706406=575985750664031168 
total=575985750664031168+6973568802=575985757637600000 
total=575985757637600000+129140163=575985757766740160 
total=575985757766740160+28697814=575985757795437952 
total=575985757795437952+1594323=575985757797032256 
total=575985757797032256+177147=575985757797209408 
total=575985757797209408+59049=575985757797268480 
total=575985757797268480+6561=575985757797275072 
total=575985757797275072+4374=575985757797279424 
total=575985757797279424+729=575985757797280128 
total=575985757797280128+81=575985757797280192 
total=575985757797280192+2=575985757797280192 
Case #37: 575985757797280192 

Как вы можете видеть, в какой-то момент добавление просто работает некорректно (например 575985757797279424 + 729 = 575985757797280153 не 575985757797280128)

Я невероятно дю Этим поведением было бы очень признано любое возможное объяснение.

+6

Получить bignum библиотека. Числа с плавающей запятой не обеспечивают точной арифметики, даже если все операнды являются целыми числами. – user2357112

+0

Какую проблему вы испытываете? – MikeCAT

+0

Я думаю, вы должны сделать массив shortint и создать собственное дополнение между массивом. Это легко, и см. Выше комментарий, почему вы не должны использовать с плавающей запятой – AchmadJP

ответ

1

Вы достигли пределов точности для выбранного типа с плавающей точкой.

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

Однако цифры, которые у вас здесь, будут вписываться в 64-битное целое число. Почему бы просто не использовать это и не сэкономить?

+2

Ему не нужна библиотека bignum. Все его номера хорошо вписываются в int64. – Soonts

+0

@ Сунты: хорошая точка –

0

Двойник имеет 3 компонента знак, показатель, доля. Например, 1.2345 представлен как 12345 * 10power-4

Несмотря на то, что Double имеет такой же длинный размер, он имеет несколько бит, предназначенных для экспоненциальной части, поэтому точность меньше длины длинного, которая дает поплавок с точностью до 7 десятичных знаков цифры и двойной точностью 16 десятичных digits.Since арифметики с плавающей точкой не точны после того, как заданное число цифр

Кроме чтения
1. https://chortle.ccsu.edu/java5/Notes/chap11/ch11_2.html
2. http://codeforces.com/blog/entry/1521?#comment-28329 (около мощн в C++)