2014-09-05 19 views
21
#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

int main() 
{ 
    int n,i,ele; 
    n=5; 
    ele=pow(n,2); 
    printf("%d",ele); 
    return 0; 
} 

L'uscita è 24.Perché pow (n, 2) restituisce 24 quando n = 5, con il mio compilatore e il mio sistema operativo?

Sto usando GNU/GCC in Code :: Blocks.

Cosa sta succedendo?

so la funzione pow restituisce un double, ma 25 adatta un tipo int Allora perché questo codice stampa un 24 invece di un 25? Se il codice n=4; n=6; n=3; n=2; funziona, ma con il cinque no.

+0

Utilizzare 'float ele;' (e il formato di stampa '% f', come nel * precedente * codice) - cosa viene visualizzato? – user2864740

+1

Puoi provare a prendere il valore di ritorno di 'pow' in una variabile' float' o 'double', quindi prova a convertirlo in' int'. Vedi se questo produce anche '24' o la risposta corretta' 25' –

+0

@ Don'tYouWorryChild ya che funziona, ma perché non posso prendere il valore di ritorno di un pow in un int ?. In un test l'assistente mi ha detto "si puoi usare un int per ottenere il ritorno di un pow", quindi ... ha torto? – exsnake

risposta

22

Ecco cosa potrebbe accadere qui. Dovresti essere in grado di verificare ciò osservando l'implementazione del tuo compilatore della funzione pow:

Supponendo di avere l'inclusione corretta, (tutte le risposte e i commenti precedenti sono corretti - non prendere i file #include per scontato), il prototipo per la funzione standard pow è questo:

double pow(double, double);

e si sta chiamando pow come questo:

pow(5,2);

La funzione pow passa attraverso un algoritmo (probabilmente utilizzando i logaritmi), quindi utilizza funzioni e valori in virgola mobile per calcolare il valore di potenza.

La funzione pow non passare attraverso un ingenuo "moltiplicare il valore di x un totale di n volte", in quanto si deve calcolare anche pow usando esponenti frazionari, e non è possibile calcolare potenze frazionarie in questo modo.

Quindi più che probabile, il calcolo di pow utilizzando i parametri 5 e 2 ha provocato un leggero errore di arrotondamento. Quando hai assegnato a un int, hai troncato il valore frazionario, ottenendo così 24.

Se si utilizzano numeri interi, si potrebbe scrivere la propria funzione "intpow" o simile che semplicemente moltiplica il valore il numero richiesto di volte .I vantaggi di questo sono:

  1. Non si ottiene nella situazione in cui è possibile ottenere gli errori di arrotondamento sottili usando pow.

  2. La tua funzione intpow verrà probabilmente eseguita più rapidamente di una chiamata equivalente a pow.

+13

Se stai per lanciare il tuo intero potere, dovresti probabilmente usare [esponenziazione per quadratura] (http://en.wikipedia.org/wiki/Exponentiation_by_squaring) piuttosto che ripetuta moltiplicazione poiché quest'ultima è ** O (n) ** e il primo è ** O (log n) **. – aruisdante

+2

@aruisdante: Attenzione, la notazione suggerisce uno spostamento dalla complessità lineare a quella logaritmica, quando in realtà è uno spostamento da [pseudo-lineare] (https://en.wikipedia.org/wiki/Pseudo-polynomial_time) a complessità lineare. –

+1

@BenVoigt Tecnicamente, il commento precedente avrebbe dovuto essere più specifico: l'algoritmo ingenuo richiede operazioni aritmetiche O (n) (moltiplicazione o aggiunta) dove n è l'esponente; la quadratura riduce questo a O (log (n)). Se prendiamo il numero di bit in n come dimensione del problema, potremmo anche voler contare il numero di bit in ogni prodotto e non considerare la moltiplicazione come un'operazione a tempo costante. Per le preoccupazioni pratiche delle persone che fanno calcoli numerici, penso che la pagina di Wikipedia sia eccessivamente pedante; per questioni di complessità teorica, la sua correttezza è discutibile. –

1

Se non #include <math.h> il compilatore non conosce i tipi degli argomenti per pow() che sono entrambi double non int - in modo da ottenere un risultato indefinito. Si ottiene 24, ottengo 16418.

+0

OP include math.h. non è una possibilità di ottenere un risultato leggermente fuori da non includere matematica.h. quindi noi un problema completamente diverso. –

1

Quando si utilizza pow con le variabili, il suo risultato è double. Assegnare ad un int lo tronca.

Quindi è possibile evitare questo errore assegnando il risultato della variabile pow a double o float.

Quindi sostanzialmente

si traduce in exp(log(x) * y) che produrrà un risultato che non è esattamente lo stesso come x^y - solo un quasi approssimazione come un valore in virgola mobile ,. Quindi, per esempio, 5^2 diventerà 24.9999996 o 25.00002

+0

ho chiesto in un test per l'assistente che parlava di usare un ist istantaneo un doppio in un test, e ha detto sì, usare un int. Ma ora capisco che si sbagliava. – exsnake

+0

L'assistente dei tuoi insegnanti deve rendersi conto che non si dovrebbero chiamare funzioni che sono pensate per i tipi 'double' e si presuppone che userà un'implementazione basata su' integer'. – PaulMcKenzie

2

Si desidera che int sia il risultato di una funzione destinata al doppio.

Si dovrebbe forse usare

ele=(int)(0.5 + pow(n,2)); 
/* ^^   */ 
/* casting and rounding */ 
+0

Meglio usare 'ele = round (0.5 + pow (n, 2));'. Anche se in questo caso 'pow (n, 2)' non dovrebbe restituire risultati minori di zero, 'y = (int) (0.5 + x)' è un problema per 'x' negativo. – chux

+6

Non meglio! dovresti semplicemente usare 'round (pow (n, 2))'. aggiungendo 0,5 prima dell'arrotondamento si arrotonda efficacemente al prossimo numero intero. Se 'pow (n, 2)' ha restituito 25 più epsilon, otterresti 26. – chqrlie

1

Floating-point arithmetic is not exact.

Sebbene piccoli valori possono essere aggiunti e sottratti esattamente, la funzione pow() funziona normalmente moltiplicando logaritmi, quindi, anche se gli ingressi sono entrambi esatta, il risultato non è. Assegnazione di int tronca sempre, quindi se l'inesattezza è negativo, si otterrà 24 invece di 25.

La morale di questa storia è quello di utilizzare le operazioni su interi interi, e diffidare di <math.h> funzioni quando gli argomenti reali sono essere promosso o troncato. È spiacevole che GCC non avvisi se non si aggiunge -Wfloat-conversion (non è in -Wall -Wextra, probabilmente perché ci sono molti casi in cui tale conversione è prevista e desiderata).

Per potenze di interi, è sempre più sicuro e più veloce usare la moltiplicazione (divisione se negativo) piuttosto che pow() - riservare quest'ultimo per dove è necessario! Siate consapevoli del rischio di overflow, però.

Problemi correlati