-2
votes

Float et double arithmétique ne renvoient pas de résultats précis?

Swift / iOS Mise en place de certains arithmétiques sur les prix des actions, faisant une soustraction pour arriver à une perte / gaine quotidienne

Remarque: ce ne sont pas des calculs comptables, ils sont tous sur la mesure de la performance de l'investissement, donc une précision absolue n'est pas nécessaire. , au contraire, la priorité est de compléter les milliards de calculs en peu de temps que possible (sous-seconde) - d'où l'utilisation d'arithmétiques de points flottants. Le problème que j'ai décrit ci-dessous devient important car une très petite erreur de multiplication peut devenir significative à l'échelle que j'effectue les calculs. P>

Lorsque vous utilisez le type de flotteur par défaut, je reçois des résultats inexacts (voir Code de jeu) ci-dessous. . P>

import UIKit

var str = "Hello, playground"

let y_float: Float = 129.08

let t_float : Float = 130.29

let y: Double = Double(y_float) // results in 129.0800018310547 !!!

let t: Double = Double(t_float) // results in 130.2899932861328

let subtracted : Double = t - y

let returnVal = subtracted / y


15 commentaires

Peut-être que c'est un erreur d'arrondi à virgule flottante ?


Float a une précision de ~ 6 chiffres décimaux ...


J'accepterais l'erreur d'arrondi si l'erreur était la même que pour la feuille de calcul - I.E. 1.209998 ou quelque chose de similaire.


La feuille de propagation utilise probablement une représentation avec une précision supérieure (telle que double )


Martin R - L'erreur d'arrondi dans la feuille de calcul est différente (c'est-à-dire que la feuille de calcul est plus précise). Je suis intéressé par les mécanismes exacts au travail et pourquoi il y a une différence entre le tableur et le code.


Un autre commentaire - désolé d'être verbeux. Je comprends qu'il peut y avoir une erreur d'arrondi, mais la conséquence est que si je veux comparer avec une feuille de calcul pour vérifier les résultats, je dois limiter le résultat dans le code et dans la feuille de calcul à 4 décimales, car les numéros de source sont 2 décimales. . C'est un peu gênant et ajoute du code supplémentaire.


Avec point flottant à double précision ( double ), vous obtiendrez 1,209999999999999795, et arrondir cela à 14 chiffres décimaux donne 1,209999999999998. Que pourrait quelle est votre tableur.


Votre problème d'arrondi est sans importance, si vous soustrayez deux chiffres avec une précision à 2 chiffres, la réponse n'a qu'une précision à deux chiffres et rien de plus. Semblable pour la division


Related: est floating Point Math cassé? - avec des liens vers une documentation supplémentaire, telle que < Un href = "https://docs.oracle.com/cd/e19957-01/806-3568/ncg_goldberg.html" rel = "NOFOOL NOREFERRER"> Ce que chaque scientifique informatique doit connaître sur l'arithmétique de point flottant .


Jockim Danielson - convient que c'est le cas, je suis juste un peu judicieux que le complier ne peut pas prendre soin de couper la poubelle. Je devrai ajouter le code similaire à suggéré par Aulparmar ci-dessous pour corriger les calculs de l'application et de la feuille de calcul. Je suppose que cela fait partie de pourquoi Swift est rapide.


@TOMMP: flotter et double sont des chiffres de points flottants binaires, et aucun d'entre eux ne peut stocker le nombre 129.08 exactement - essayez let Y_Float: float = 129.08; Imprimer (chaîne (format: "% .14f", y_float)) . Seul a l'air comme si la conversion en double ajout de la poubelle, car une double est (par défaut) imprimée avec des chiffres plus fractionnaires.


@Martin R: Merci pour les réponses. Je suppose que je dois mordre la balle et faire une coupure dans le code et le tableur pour obtenir la cohérence.


Utilisez toujours décimal pour représenter des valeurs financières, telles que les prix des actions.


La conversion de float à double ne modifie pas le tout des valeurs. La déclaration Soit Y_Float: Float = 129.08 Ensems y_float à exactement 129.0800018310546875. Certaines formatage par défaut pour cela peuvent afficher la valeur sous la forme "129.08000" ou un affichage similaire car le formatage par défaut utilise seulement quelques chiffres pour float . Lorsqu'il est converti en double , la valeur est exactement la même. Mais le formatage par défaut pour double utilise plus de chiffres, il peut donc montrer quelque chose comme "129.08000183105469".


@ Dávid Pásztor: Pour clarifier, cette question ne concerne pas la représentation des prix des actions, elle concerne le calcul des rendements de pourcentage et des écarts qui, de leur nature même, ne sont pas des montants finis.


3 Réponses :


1
votes

Utilisez Double

let y: Double = 129.08

let t: Double = 130.29

let subtracted: Double = t - y


1 commentaires

Ok donc j'avais essayé avec double plus tôt et j'ai trouvé les résultats incompatibles avec la feuille de calcul. Est-ce que je viens d'essayer à nouveau et constaté que la conversion d'un flotteur à un double semble ajouter des ordures dans les chiffres de signification faibles !!



-2
votes

ok donc j'ai regardé autour de moi et j'ai trouvé

Arrondir une double valeur sur x Nombre de décimales à Swift

que je vais utiliser pour ranger les valeurs de points flottants et supprimer l'inexactitude. Je vais également mettre en œuvre une troncature similaire dans ma feuille de calcul pour assurer l'alignement.

Voici le code: xxx


2 commentaires

C'est généralement une mauvaise idée. "Arrondir" des chiffres pour les faire Good Good En décimal n'améliore pas leur qualité mathématique. Il introduit une erreur supplémentaire. Si vous devez calculer une sorte d'unités entières (nombre de personnes, cupcakes, cents, millièmes de la part d'actions, quoi que ce soit), alors l'arithmétique entier est souvent un meilleur choix. Si vous allez utiliser des arithmétiques de point flottant, il est important de véritablement Comprendre Arithmétique à point flottant (apprendre sa représentation et les règles de son arithmétique) plutôt que d'appliquer des correctifs kludgy.


@ERIC PostPischil - Appréciez le point que vous faites, merci. Je répète où j'utilise des valeurs flottantes / doubles ou décimales. J'ai appris des choses intéressantes en ce qui concerne le flotteur / double aujourd'hui - toujours pas convaincu que cela fonctionne comme il se doit. Comme cela arrive, l'utilisation que je fais du flotteur / double dans ce cas est valide parce que je suis informatique% de retour et de variance de probabilités plutôt que de suivre des prix absolus ou des chiffres de titres.



0
votes

float et double utilisez un codage interne de base-2 afin qu'il y aura toujours des valeurs de base-10 qu'ils ne peuvent pas représenter avec précision.

Si vous souhaitez utiliser de véritables calculs décimal (base-10), utilisez le type décimal. : xxx

Notez que j'ai utilisé des chaînes pour initialiser les valeurs car les littéraux seraient d'abord traités comme flottant et produiraient les mêmes inexactitudes avant les assignations.


1 commentaires

La performance des calculs utilisant décimale plutôt que float / double sera intéressante. J'ai l'intention de faire littéralement des milliards de multiplications sur ces valeurs en temps réel en utilisant du métal. Je me promène également si la représentation d'une décimale est compatible avec le métal - je devine non.