2015-06-29 12 views
5

Ho due campi per la memorizzazione dei dati di geolocalizzazione, definiti come raddoppia nel mio database MySQL:Strano cambiamento valore quando il salvataggio dei dati di tipo doppio (geolocalizzazione) nella base di dati

`address_geo_latitude` float(10,6) NOT NULL, 
`address_geo_longitude` float(10,6) NOT NULL 

e sto usando Yii2 di double validatore su valori passati dall'utente:

public function rules() 
{ 
    return [ 
     [['address_geo_latitude', 'address_geo_longitude'], 'double', 'min'=>0, 'max'=>360] 
    ]; 
} 

(anche se i miei test sembra essere dimostrando, che la questione non ha nulla a che fare con validatori Yii2)

Durante le prove I'v e ha osservato strani cambiamenti di valori, vale a dire (?):

  • 359.90 diventa 359.899994 (0,000006 differenza),
  • 359.80 diventa 359.799988 (0,000012 differenza),
  • 311.11 diventa 311.109985 (0,000015 differenza),
  • 255.55 diventa 255.550003 (-0,000003 differenza),
  • 205.205 diventa 205.205002 (-0,000002 differenza),
  • 105.105 diventa 105.105003 (-0,000003 differenza).

ma:

  • 359.899994 rimane 359.899994,
  • 311.109985 rimane 311.109985,
  • 311 rimane 311,
  • 255 rimane 255,
  • 200 resti 200,
  • 75.75 rimane 75.75,
  • 11.11 rimane 11.11.

Cosa mi manca? Non riesco a vedere alcun modello o logica dietro questi.

È questo, perché ho una dichiarazione di campo MySQL errata per questo tipo di dati? Se sì, allora qual è quella corretta? Poche risposte diverse:

suggerisce che l'uso float(10,6) è l'opzione migliore, se non si utilizza MySQL di spatial extensions.

miei test sembra dare i suoi, che la questione non ha nulla a che fare con validatori Yii2, perché il valore rimane corretta fino rileggere dal database:

print_r(Yii::$app->request->post()); //Correct! 
print_r($lab->address_geo_latitude); //Correct! 

if ($lab->load(Yii::$app->request->post(), 'Lab') && $lab->save()) { 
    print_r($lab->address_geo_latitude); //Correct! 

    $lab2 = $this->findModel($lab->id); 
    print_r($lab2->address_geo_latitude); //<-- HERE! Incorrect! 
} 

La mia domanda è in contrasto con this one. I miei numeri guadagna, non perde, precisione! E solo per determinati numeri, non sempre.

+0

i valori sono corretti in * mysql * dopo averli salvati di nuovo? – Tony

+0

@Tony Scusa, non capisco la tua domanda, perché non ho mai detto nulla sul secondo salvataggio, solo sulla seconda lettura (riletta). Sì, immediatamente dopo il valore '$ model-> save()' salvato come '$ model-> address_geo_latitude = 311.11' risulta effettivamente memorizzare/avere il valore' 311.109985' nella colonna 'address_geo_latitude'. – trejder

risposta

2

Questo accade non a causa di Yii ma a causa del modo in cui i valori in virgola mobile vengono memorizzati su sistemi binari.

Come si può leggere nei MySQL documentation "Problemi con valori in virgola mobile":

numeri a virgola mobile a volte provocano confusione perché sono indicativi e non memorizzati come valori esatti. Un valore a virgola mobile come scritto in un'istruzione SQL potrebbe non essere uguale al valore rappresentato internamente.

Here you can find the great explanation per questo problema con esempi. Come puoi vedere i numeri possono diventare un po 'più grandi, più piccoli o non modificati, ma devi sempre ricordare che questa è solo un'approssimazione.

Per i dati di collocazione è possibile utilizzare il semplice DECIMAL type per assicurarsi che i valori siano memorizzati nel database o utilizzare Spacial Data type ottimizzato per archiviare e interrogare i dati che rappresentano gli oggetti definiti in uno spazio geometrico.

+0

Come ho scritto nella mia domanda (o forse?) L'arrotondamento o l'approssimazione mi sono noti, ma non ha nulla a che fare con questo problema. L'arrotondamento è sempre verso il numero più vicino, sia in programmazione che in matematica. Si tratta di perdere la precisione, non guadagnarla. Non è possibile chiamare la modifica di '105.105' in' 105.105003' a _rounding_ perché non si tratta di un arrotondamento e si tratta di un'operazione assurda e matematicamente errata. – trejder

+1

@trejder una versione precedente della documentazione di mysql menzionata nella risposta https://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html ha un buon esempio di come possono essere diversi i numeri in virgola mobile rappresentato quando aggiungi più posizioni decimali, quindi prova a usare * decimal * invece di * float * e confronta i risultati – Tony

+0

@Bizley, puoi rieditare la tua risposta, includendo la maggior parte di questi commenti qui e magari collegando [questa risposta] (http : //stackoverflow.com/a/163084/1469208). Hai effettivamente risolto il problema! :> Cambiare 'float (10,6)' a 'decimal (9,6)' fa miracoli e non appare più alcun cambiamento di valore. Sarò felice di accettare la tua risposta, una volta che la si riedificherà. – trejder

Problemi correlati