Voici un code simple dans Xcode 7.3.1 aire de jeux:
var str = "8.7" print(Double(str))
la sortie est surprenante: Optional(8.6999999999999993)
aussi, Float(str)
donne: 8.69999981
Des pensées ou des raisons sur ce gars? Toute reference à ceci serait appréciée.
Aussi, comment puis-je convertir "8.7" en 8.7 en tant que Double (ou Float)?
modifier
dans swift:
(str comme NSSsortingng) .doubleValue renvoie 8.7
Maintenant, c'est ok. Mais ma question, encore, n'obtient pas une réponse complète. Nous avons trouvé une alternative mais pourquoi ne pouvons-nous pas countr sur Double ("8.7"). S'il vous plaît, donnez un aperçu plus profond à ce sujet.
Modifier 2
("6.9" comme NSSsortingng) .doubleValue // imprime 6.9000000000000004
Donc, la question s'ouvre à nouveau.
Il y a deux problèmes différents ici. D'abord – comme déjà mentionné dans les commentaires – un nombre à floating point binary ne peut pas représenter le nombre 8.7
précisément. Swift utilise la norme IEEE 754 pour représenter les nombres à floating point simple et double précision, et si vous affectez
let x = 8.7
alors le nombre représentable le plus proche est stocké dans x
, et c'est
8.699999999999999289457264239899814128875732421875
Beaucoup plus d'informations à ce sujet peuvent être trouvées dans l'excellente Q & A Mathématiques à floating point est cassé? .
Le deuxième problème est: Pourquoi le numéro est-il parfois imprimé en "8.7" et parfois en "8.6999999999999993"?
let str = "8.7" print(Double(str)) // Optional(8.6999999999999993) let x = 8.7 print(x) // 8.7
Est-ce que Double("8.7")
différent de 8.7
? Est-ce que l'un est plus précis que l'autre?
Pour répondre à ces questions, nous devons savoir comment fonctionne la fonction print()
:
CustomSsortingngConvertible
, la fonction d'printing appelle sa propriété description
et imprime le résultat dans la sortie standard. CustomDebugSsortingngConvertible
, la fonction d'printing appelle debugDescription
et debugDescription
le résultat dans la sortie standard. Le type Double
est conforme à CustomSsortingngConvertible
, donc
let x = 8.7 print(x) // 8.7
produit la même sortie que
let x = 8.7 print(x.description) // 8.7
Mais que se passe-t-il
let str = "8.7" print(Double(str)) // Optional(8.6999999999999993)
Double(str)
est facultatif et struct Optional
n'est pas conforme à CustomSsortingngConvertible
, mais à CustomDebugSsortingngConvertible
. Par conséquent, la fonction d'printing appelle la propriété debugDescription
de Optional
, qui à son tour appelle la debugDescription
du Double
sous-jacent. Par conséquent – en plus d'être un optionnel – le nombre de sortie est le même que dans
let x = 8.7 print(x.debugDescription) // 8.6999999999999993
Mais quelle est la différence entre description
et debugDescription
pour les valeurs à floating point? À partir du code source Swift, on peut voir que les deux appellent finalement la fonction swift_floatingPointToSsortingng dans Stubs.cpp , avec le paramètre Debug
défini sur false
et true
, respectivement. Cela contrôle la précision du nombre à convertir la string:
int Precision = std::numeric_limits<T>::digits10; if (Debug) { Precision = std::numeric_limits<T>::max_digits10; }
Pour la signification de ces constantes, voir http://en.cppreference.com/w/cpp/types/numeric_limits :
digits10
– nombre de numbers décimaux pouvant être représentés sans changement, max_digits10
– nombre de numbers décimaux nécessaires pour différencier toutes les valeurs de ce type. Ainsi, la description
crée une string avec less de numbers décimaux. Cette string peut être convertie en Double
et revenir à une string donnant le même résultat. debugDescription
crée une string avec plus de numbers décimaux, de sorte que deux valeurs à floating point différentes produisent une sortie différente.
Résumé:
description
et debugDescription
des types floating point utilisent une précision différente pour la conversion en string. En conséquence, Par conséquent, dans votre cas, vous voulez probablement déballer l'option avant de l'imprimer:
let str = "8.7" if let d = Double(str) { print(d) // 8.7 }
Pour un meilleur contrôle, utilisez NSNumberFormatter
ou une printing formatée avec le format %.<precision>f
.
Une autre option peut être d'utiliser (NS)DecimalNumber
au lieu de Double
(par exemple pour les montants en devise), voir par exemple Round Issue dans swift .
J'utiliserais:
let doubleValue = NSNumberFormatter().numberFromSsortingng(str)?.doubleValue
Vous pouvez utiliser ce code peut être utile.
print(str.doubleValue)