2016-01-20 17 views
17

Oggi ho appena fatto una scoperta interessante durante il test cosa succede calcolo bitwisely in php come INF^0 (^ => bit per bit operatore per OR esclusivo (XOR)) quello che mi ha dato int(-9223372036854775808) => massimo possibile valore negativo in un sistema a 64 bit.di PHP in operazioni bit per bit restituisce valori strani

Ma poi mi chiedevo: "Perché il risultato andando negativo XOR quando il "Infinit positiva" significa 9223372036854775807 (63 bit su 1 con una primaria 0) e 0 (64 Bits on 0 =>0 xor 0 = 0) Cosa il valore infinito di PHP è comunque e qual è il calcolo dietro di esso? E perché ottengo un valore negativo (corretto?) quando uso "infinito negativo" (A 1 leader su uno 0 su 0 =>1 xor 0 = 1? ".

Un altro punto interessante è che questo accade solo su PHP versione 5.5.9-1, e non ad esempio su 5.3.x. e 5.6.x (dove l'ho testato)! Forse qualcuno ha un'idea di cosa succede Là? Testato su tre versioni, ma solo mia (5.5.9-1) dà questi risultati:

Bitwise operations

Solo per farvi sapere, è solo un playaround abstract che ho fatto per divertimento, ma trovo che sia interessante. Forse qualcuno può aiutare qui o spiegarmi un pensiero sbagliato che ho? Dimmi solo se qualcuno ha bisogno di più informazioni su qualsiasi cosa!

EDIT: Di conseguenza per jbafford sarebbe bello ottenere un answere completa, quindi mi limiterò a lui cito: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?

+3

'-9223372036854775808' è il massimo valore negativo possibile __per un intero (64 bit) __.... 'INF' non è un numero intero, ma un [IEE754 float] (https://en.wikipedia.org/ wiki/IEEE_754-1985) –

+1

Pensi che il problema sia probabilmente nel confronto bit a bit da 'float (INF)' a 'int (0)'? Sai come funziona? –

+3

Si stanno utilizzando operazioni bit a bit su un valore float a 64 bit, ma l'utilizzo di operazioni bit a bit considera il valore come se fosse un valore intero a 64 bit 'Gli operatori bitwise consentono la valutazione e la manipolazione di bit specifici all'interno di __integer __.' ... .. quindi è un confronto fallace. Gli op bit a bit non digitano correttamente se li stai eseguendo contro un float, perché sono interessati al livello di bit, ma imposteranno il tipo di dati risultante su un numero intero –

risposta

7

Innanzitutto, ^ sé non è ciò che è speciale qui. Se si XOR qualcosa con zero, o O qualsiasi cosa con zero, si ottiene solo la risposta originale. Quello che vedi qui non fa parte dell'operazione stessa, ma piuttosto cosa succede prima dell'operazione: gli operatori bit a bit prendono interi, quindi PHP converte il float in un intero. È nella conversione float-integer che appare il comportamento strano e non è esclusivo per gli operatori bit a bit. Succede anche per (int), per esempio.

Perché produce questi risultati strani? Semplicemente perché questo è ciò che il codice C PHP è scritto in produce quando converte un float in un intero. Nello standard C, il comportamento di C per le conversioni flottante a-intero è indefinito per i valori speciali di INF, -INF e NAN (o, più precisamente, per "parti integranti" un numero intero non può rappresentare: §6.3.1.4). Questo undefined behaviour significa che il compilatore è libero di fare tutto ciò che vuole. In questo caso, in questo caso, il codice generato genera il valore intero minimo qui, ma non è garantito che ciò accada sempre e non è coerente su piattaforme o compilatori. Perché il comportamento è cambiato tra 5.4 e 5.5? Perché il codice di PHP per la conversione di float in numeri interi changed to always perform a modulo conversion.Questo ha risolto il comportamento indefinito per numeri in virgola mobile molto grandi, ma non ha ancora controllato i valori speciali, quindi per quel caso ha prodotto ancora un comportamento indefinito, solo leggermente diverso questa volta.

In PHP 7, ho deciso di ripulire questa parte del comportamento di PHP con l'Integer Semantics RFC, il che rende il check PHP per i valori speciali (INF, -INF e NAN) e li converte in modo coerente: hanno sempre convertono a intero 0. Non c'è più un comportamento indefinito al lavoro qui.


Ad esempio, un programma di test che ho scritto in C per tentare di convertire infinito in un numero intero (specificamente un gruppo C long) ha risultati diversi da 32 bit e 64 bit costruisce. La versione a 64 bit produce sempre -9223372036854775808, il valore intero minimo, mentre la generazione a 32 bit produce sempre 0. Questo comportamento è lo stesso per GCC e clang, quindi immagino che entrambi producano un codice macchina molto simile.

Se si è tentato di convertire un galleggiante per un intero, e il valore di tale galleggiante era troppo grande per essere un numero intero (ad esempio PHP_INT_MAX * 2, o PHP_INT_MIN * 2), il risultato è stato indefinito. PHP 5.5 rende il risultato coerente, sebbene non intuitivo (agisce se il float è stato convertito in un numero intero molto grande e i bit più significativi sono stati scartati).

+0

Questa era la risposta che stavo cercando! Grazie mille :-) –

+0

Sono contento che ti sia piaciuto! (Anche se non mi interessa davvero, potresti voler assegnare la taglia.) – Andrea

4

tuo float(INF) ottiene implicitamente fusa in un intero.

e XOR con 0 non modifica il primo parametro. Quindi in pratica questo è solo un cast da float a int che non è definito per valori che non sono nell'intervallo intero. (Per tutti gli altri valori verrà troncato verso zero)

https://3v4l.org/52bA5

+3

Questo in realtà non risponde alla parte più interessante della domanda, che è, perché i risultati 5.5 e 5.6 in PHP_INT_MIN, e tutto il resto restituisce 0? – jbafford

+0

probabilmente perché è ciò che restituisce la funzione C sottostante. Ma dal momento che il risultato non è definito potrebbe essere qualsiasi numero arbitrario e sarebbe comunque un risultato "corretto" – belst

+2

Beh, sì, certo. Ma una risposta interessante sarebbe * cosa specificamente * cambiato (e perché) in 5.5 e 7. – jbafford

Problemi correlati