2015-11-13 3 views
2

Я показал два фрагмента кода. Я не совсем понимаю, как использование pow() по-разному приводит к различию в этих кодах. Заранее большое спасибо.различные ответы с использованием pow() в C++ при использовании в разных местах, хотя такой же ожидается

В этой задаче вы должны вычислить сумму всех целых чисел от 1 до n, но вы должны брать все степени в два с минусом в сумме. Например, для n = 4 сумма равна -1, 2 + 3 - 4 = - 4, поскольку 1, 2 и 4 равны 2 , 2 и 2 соответственно. Вычислите ответ для t значений n.

#include<bits/stdc++.h>  
typedef long long ll; 
typedef double dl; 
using namespace std; 
int main() { 
    ll n,t; 

    ll i,cnt=0; 
    cin>>t; 
    while(t--)// for 't' number of test cases 
    { 
     cin>>n; 

      for(i=1,cnt=0;i<=n;i*=2,cnt++); //counting number of terms in the GP:1,2,4,.... 
      cout<<setprecision(20)<<((n*(n+1))/2)-(2*(pow(2,cnt)-1))<<endl; 
    } 
    return 0; 

} 
//output for above code:499999998352516352 
// and the slightly modified code.. 


#include<bits/stdc++.h> 
typedef long long ll; 
typedef double dl; 
using namespace std; 
int main() { 
    ll n,t; 

    ll i,cnt=0; 
    cin>>t; 
    while(t--)// for 't' number of test cases 
    { 
    cin>>n; 

    for(i=1,cnt=0;i<=n;i*=2,cnt++); 
    ll k=(pow(2,cnt)); //instead of directly printing the answer, 'k' is computed and then used to find the answer. 
    cout<<setprecision(20)<<((n*(n+1))/2)-(2*(k-1))<<endl; 
    } 
    return 0; 

} 
//output for above code:499999998352516354 
// the second one is the correct answer, the first one is wrong. how does pow() change the values here? 
+5

'pow()' работает (и возвращает) число с плавающей запятой. Номера с плавающей запятой по сути неточно. –

+0

Спасибо, но как мы узнаем, какое использование будет работать должным образом? – Sreenidhi

+5

Определите «правильно». Числа с плавающей запятой по сути своей неточны. Вы можете только спросить, допустима ли ошибка согласования в пределах допустимого допуска. Посмотрите на [что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://floating-point-gui.de/) для деталей. – Angew

ответ

2

Очевидно значение, что дает вам неприятности является n=1000000000, или 10 . Наибольшая интегральная мощность 2 меньше или равна этому значению 2 . Таким образом, сумма, которую вы пытаетесь вычислить, равна (10^9 * (10^9 + 1))/2-2 * (2^30-1) или 500000000500000000-2147483646, или 499999998352516354.

Ваш второй подход работает, потому что силы двух точны и потому, что вы используете целочисленную арифметику в вычитании. Ваш первый подход терпит неудачу, потому что выражение вычисляется как double. Первый термин, n*(n+1)/2 или 500000000500000000, является «точным», что означает, что в представлении с плавающей точкой нет ошибки. Второй термин, 2147483646, также является точным. Проблема в этом случае происходит с вычитанием. Разница между двумя неточна, что означает, что вы потеряли точность.

У вас не было причин использовать pow. Вы уже рассчитали pow(2,cnt). На самом деле вам совсем не нужно cnt. Просто используйте

ll k; 
for(k=1; k<=n; k*=2);