Quando una funzione di trigger, con un argomento di laurea, dovrebbe restituire -0,0?


10

Nel creare funzioni trigonometriche my_sind(d), my_cosd(d), my_tand(d), quello utilizzato un argomento grado piuttosto che un radiante e fornito risposte esatte a multipli di 90, ho notato che il risultato era talvolta -0.0piuttosto che 0.0.

my_sind( 0.0) -->  0.0
my_sind(-0.0) --> -0.0

my_sind(180.0) --> -0.0
my_sind(360.0) -->  0.0

sin()e in tan()genere restituisce lo stesso risultato zero segno per un dato input zero segno. Ha senso che my_sin()dovrebbe corrispondere sin()per quegli input.

my_sind( 0.0) alike sin( 0.0) -->  0.0
my_sind(-0.0) alike sin(-0.0) --> -0.0

La domanda è : per quale numero intero non_zero_ndovrebbe / potrebbe il risultato mai tornare -0.0per my_sind(180*non_zero_n), my_cosd(180*n + 180), my_tand(180*non_zero_n)?

È abbastanza facile da codificare, quindi f(-0.0)produce solo -0.0ed è fatto con esso. Semplice chiedersi se c'è qualche motivo per fare altro f(x) ritorno -0.0per qualsiasi altro ( diverso da zero ) xe l'importanza di assicurare quel segno.


Nota: questa non è una domanda sul perché si verifica 0.0vs. -0.0Questo non è il motivo per cui cos(machine_pi/4)non ritorna 0.0. Né questa è una domanda su come controllare la generazione di 0.0o -0.0. Lo vedo meglio come una domanda di design.

Risposte:


4

Il principio progettuale di "minima sorpresa" suggerisce che guardiamo a funzionalità precedentemente stabilite per la guida. In questo caso, la funzionalità stabilita vicina è fornita da sinpie cospifunzioni introdotte in IEEE Std 754-2008 (IEEE Standard per aritmetica in virgola mobile), sezione 9. Queste funzioni non fanno parte delle attuali norme ISO C e ISO C ++, ma sono stati integrati nelle librerie matematiche di varie piattaforme di programmazione, ad esempio CUDA.

Queste funzioni calcolano sin (πx) e cos (πx), dove la moltiplicazione con π si verifica implicitamente all'interno della funzione. tanpinon è definito, ma potrebbe, in base all'equivalenza matematica, assumere che funzioni secondo tanpi(x) = sinpi(x) / cospi(x).

Possiamo ora definire sind(x) = sinpi(x/180), cosd(x) = cospi(x/180), tand(x) = tanpi(x/180)in modo intuitivo. La sezione 9.1.2 di IEEE-754 spiega la gestione di argomenti speciali per sinpie cospi. In particolare:

sinPi (+ n) è +0 e sinPi (−n) è −0 per numeri interi positivi n. Ciò implica, in appropriate modalità di arrotondamento, che sinPi (-x) e -sinPi (x) sono lo stesso numero (o entrambi NaN) per tutti x. cosPi (n + ½) è +0 per qualsiasi numero intero n quando n + ½ è rappresentabile.

Lo standard IEEE 754-2008 non fornisce una logica per i requisiti citati, tuttavia, una prima bozza della sezione pertinente afferma:

Se il valore della funzione è zero, il segno di questo 0 è meglio determinato considerando l'estensione continua della funzione di segno della funzione matematica.

L'esame dell'archivio di posta del gruppo di lavoro 754 può fornire ulteriori approfondimenti, non ho avuto il tempo di approfondire. L'implementazione sind(), cosd()e tand()come descritto sopra, arriviamo quindi a questa tabella di casi di esempio:

SIND
 angle value 
  -540 -0
  -360 -0
  -180 -0
     0  0
   180  0
   360  0
   540  0

COSD
 angle value
  -630  0
  -450  0
  -270  0
   -90  0
    90  0
   270  0
   450  0

TAND
 angle value
  -540  0
  -360 -0
  -180  0
     0  0
   180 -0
   360  0
   540 -0

5

sin () e tan () in genere restituiscono lo stesso risultato zero segno per un dato input zero segno

Potrebbe essere generalmente vero dal momento che:

  • Velocità / precisione . Per i doppi abbastanza piccoli, la migliore risposta sin(x)è x. Cioè, per numeri più piccoli di circa 1.49e-8, il doppio più vicino al seno di x è in realtà x stesso (vedi il codice sorgente glibc per sin () ).

  • Gestione di casi speciali .

    Alcune operazioni aritmetiche straordinarie sono influenzate dal segno di zero; per esempio "1/(+0) = +inf"ma "1/(-0) = -inf". Per conservare la sua utilità, il bit di segno deve propagarsi attraverso determinate operazioni aritmetiche secondo regole derivate da considerazioni di continuità.

    Le implementazioni di funzioni trascendentali elementari come sin (z) e tan (z) e i loro inversi e analoghi iperbolici, sebbene non specificate dagli standard IEEE, dovrebbero seguire regole simili. L'implementazione di sin(z) dovrebbe riprodurre sia il segno z che il suo valore az = ±O .

    ( Branch taglia per funzioni elementari complesse o molto rumore per il segno di niente di W. Kahan)

    Lo zero con 1 / sin(x)segno negativo fa eco al concetto di analisi matematica di avvicinarsi a 0 dal basso come limite unilaterale (considerare : il segno di zero fa un'enorme differenza).

MODIFICARE

Considerando il secondo punto, scrivo in my_sindmodo che:

my_sind(-0.0) is -0.0
my_sind(0.0) is 0.0

L'ultimo standard C (F.10.1.6 sine F.10.1.7 tan, implementazioni con zero con segno ), specifica che se l'argomento è ±0, viene restituito non modificato .

MODIFICA 2

Per gli altri valori penso che sia una questione di approssimazione. Dato M_PI<π:

0 = sin(π) < sin(M_PI)  1.2246467991473532e-16  +0.0
0 = sin(-π) > sin(-M_PI)  -1.2246467991473532e-16  -0.0
0 = sin(2*π) > sin(2*M_PI)  -2.4492935982947064e-16
0 = sin(-2*π) < sin(-2*M_PI)  2.4492935982947064e-16

Quindi, se my_sindfornisce risposte esatte a multipli di 180 °, può tornare +0.0o -0.0(non vedo un motivo chiaro per preferire l'uno all'altro).

Se my_sindutilizza un'approssimazione (ad esempio una degree * M_PI / 180.0formula di conversione), dovrebbe considerare come si sta avvicinando ai valori critici.


Quali sono i tuoi pensieri riguardo sind(180), sind(-180), sind(360), sind(-360),...?
chux - Ripristina Monica il

Grazie per l'aggiornamento. Forse il mio post non è chiaro. La domanda principale è dovrebbe my_trig(x)mai tornare -0.0quando |x|non lo è 0.0?
chux - Ripristina Monica il

Grazie per "Quindi se my_sind fornisce risposte esatte a multipli di 180 ° può restituire +0,0 o -0,0 (non vedo un motivo chiaro per preferire l'uno all'altro)." Finora è il punto di discussione più vicino. Sto pensando che il "principio del minimo stupore" incoraggi sempre il ritorno +0.0, ma cerco di vedere se ci sono ragioni convincenti per tornare -0.0in alcune situazioni (diverse da x == +/-0.0).
chux - Ripristina Monica il

@chux: Penso che per multipli di 180.0, si debbano davvero esaminare i valori della precisione relativa della macchina dati questi valori. Cioè, l'incremento / decremento più piccolo che dà un diverso valore rappresentabile in quel formato numerico. Quindi, confronta quel valore con il valore vero per vedere se sarebbe caduto sul lato positivo o negativo.
dal

@rwong Grazie per l'idea. Multipli di 90,0 gradi , il esatti sind(double degrees) e cosd(double degrees)valore può essere restituito: -1.0, +0.0, +1.0. Questo post è circa dovrebbe -0.0mai essere restituito (a parte sind (-0.0)). Nota: sind()non non utilizzare il semplicistico sin(x/360*M_PI)approccio.
chux - Ripristina Monica il

3

La libreria non tenta di distinguere +0 da -0. IEEE 754 si preoccupa un po 'di questa distinzione ... Ho trovato le funzioni [in matematica.h] abbastanza difficili da scrivere senza preoccuparsi del segno del nulla. - PJ Plauger, The Standard C Library , 1992, pagina 128.

Formalmente, le funzioni di trigger dovrebbero restituire il segno di zero in accordo con lo standard C ... che lascia il comportamento indefinito.

Di fronte a un comportamento indefinito, il principio del minimo stupore suggerisce di duplicare il comportamento della funzione corrispondente da math.h. Questo ha un odore giustificabile, mentre si discosta dal comportamento della funzione corrispondente in math.hodori come un modo per introdurre i bug esattamente nel codice che dipende dal segno di zero.


Le funzioni di trigger math.hnon restituiscono 0,0 quando vengono forniti argomenti come +/- pi / 2 o +/- pi poiché queste funzioni possono assumere solo valori rappresentabili vicino a +/- pi / 2, ecc. Questi valori "vicini" restituiscono risultati vicini a 0,0. Poiché le funzioni trig della libreria std ( sin cos tan) non restituiscono 0,0 (o -0,0) per qualsiasi input (tranne +/- 0,0), ma my_sind (), my_cosd (), my_tand () possono restituire 0.0 (o -0.0), c'è nessun comportamento 0.0 da duplicare.
chux - Ripristina Monica il

@chux La premessa che sin(-0.0)dovrebbe tornare -0è sospetta. Tratta un dettaglio di implementazione dello standard IEEE come principio trigonometrico. Sebbene esista un principio matematico generale di zero come limite di due intervalli incorporato nell'implementazione IEEE, si verifica a quel livello di astrazione non all'interno della trigonometria generale [da cui la variabilità in ciò che restituiscono le funzioni trigonometriche]. Il meglio che può accadere è che puoi definire una convenzione arbitraria, ma sarà divergente dalla math.hnonchalance rispetto al segno zero.
ben rudgers,

Nota: non sto suggerendo di sin(-0.0)tornare -0.0, ma che my_sind(x)dovrebbe corrispondere sin(x)quando lo xè +/-0.0. IOW: seguire la pratica precedente. Inoltre la domanda stessa è più su cosa fare quando x != 0.0, dovrebbe my_sind(x)mai tornare -0.0come in my_sind(180), ecc? Forse la tua risposta / commento risolve questo problema, ma non l'ho visto.
chux - Ripristina Monica il

@chux Se il comportamento non è definito, allora non è definito. È così com'è C. Plauger non si è preoccupato di +0contro -0quando ha scritto math.hventi anni fa. Non mi è chiaro quale problema stia risolvendo la tua agitazione per la differenza.
Ben Ruders,

1
Spero che tu veda che per un ben implementato sin(rad)per qualsiasi valore rad>0e precisione non produrrà mai 0.0come pi è irrazionale. [Ref] (www.csee.umbc.edu/~phatak/645/supl/Ng-ArgReduction.pdf) Tuttavia my_sind(deg)fornisce un esatto 0.0(o + o -) ogni multiplo di 180.0come il valore 0.0 è il risultato matematico corretto. "Principio del minimo stupore" suggerisce di restituire 0,0 in questi casi. La mia domanda è -0.0mai dovrebbe essere restituita in questi casi?
chux - Ripristina Monica il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.