Mettre en forme un nombre à virgule flottante exactement comme décimal

9

Tout point flottant binaire peut être formaté exactement en décimal. La chaîne résultante peut être quelque peu longue, mais c'est possible. Dans mon article sur la virgule flottante, je couvre l'importance de la précision, et maintenant je veux cette fonction. Ce défi consiste à écrire un programme ou une fonction qui prend une valeur à virgule flottante en entrée et formate une chaîne décimale exacte en sortie.

Pour nous assurer que nous travaillons avec les bons nombres à virgule flottante, un format précis doit être fourni en entrée du programme. Ce format sera deux entiers Significand Exponent, où la valeur réelle en virgule flottante est Significand * 2 ^ Exponent. Notez que l'une ou l'autre valeur peut être négative.

Détails:

  • La plage et la précision d'au moins un flottant de 32 bits doivent être prises en charge (aucune entrée n'ira au-delà de cela)
  • La valeur formatée décimale doit être une représentation exacte (simplement assez proche pour garantir un retour en rond correct pour flotter n'est pas assez bon)
  • Nous ne faisons pas confiance aux fonctions de formatage à virgule flottante de la bibliothèque standard pour être suffisamment correctes ou assez rapides (ex:) printf, et donc elles ne peuvent pas être utilisées. Vous devez faire le formatage. Les fonctions de formatage / conversion intégrées sont autorisées.
  • Il ne peut pas y avoir de zéros de tête ou de fin, à l'exception du zéro de tête requis devant le .s'il n'y a pas de composant de nombre entier
  • Une fonction ou un programme entier est autorisé.

Exemples:

1 -2 => 0.25
17 -3 => 2.125
-123 11 => -251904
17 50 => 19140298416324608
23 -13 => 0.0028076171875
3 120 => 3987683987354747618711421180841033728
3 -50 => 0.00000000000000266453525910037569701671600341796875
-3 -50 => -0.00000000000000266453525910037569701671600341796875
10 -2 => 2.5
-12345 -3 => -1543.125
0 0 => 0
161 -4 => 10.0625
512 -3 => 64

Le code le plus court gagne.

edA-qa mort-ora-y
la source
3
L'utilisation de l'arithmétique à virgule flottante de précision illimitée est-elle autorisée?
Dennis
2
Si l'exposant n'est pas négatif, pouvons-nous terminer avec .0?
Sp3000
@ Dennis: Oui, l'arithmétique illimitée ou à haute précision fixe est autorisée.
edA-qa mort-ora-y
1
Je pense que c'est incohérent. Si 0.abcn'est pas un zéro de début, alors ce abc.0n'est pas un zéro de fin.
orlp
1
C'est aussi la convention de toujours se terminer par .0des nombres entiers lorsqu'il s'agit de nombres à virgule flottante. Voir par exemple Python: str(1.0) == '1.0'versus str(1) == '1'. Votre logique est toujours incohérente.
orlp

Réponses:

3

CJam, 43

r_'-&\ize999rim<s1e3'0e[W%999/(i_L?\+'.*sW%

Essayez-le en ligne

Explication:

Le programme fonctionne avec des exposants jusqu'à ± 999, près de la double précision (64 bits). Il sépare le signe moins (s'il est présent) de la signification, le multiplie par 10 999 puis effectue un décalage de bit avec l'exposant, qui est maintenant un calcul exact. Il remplit ensuite vers la gauche avec des zéros si le résultat a moins de 1000 chiffres, sépare les 999 derniers chiffres comme partie fractionnaire, supprime les zéros de fin en convertissant son inverse en entier, ajoute un point décimal si nécessaire et remet tout en place.

r_         read and duplicate the significand in string form
'-&        keep only the minus sign, if present
\          swap with the other copy of the significand
iz         convert to integer and get absolute value
e999       multiply by 10^999
ri         read the exponent and convert to integer
m<         shift left by it; negative values will shift right
            the result is an exact non-negative integer
s          convert to string
1e3'0e[    pad to the left with zero characters up to length 1000
            longer strings will be left intact
            we need 1 more than 999 for the 0.xxx case
W%         reverse the string
999/       split into slices of length 999
(          take out the first slice (reversed fractional part)
i          convert to integer
            this removes the leading zeros (trailing in reverse)
_L?        if it's zero, replace with an empty string
\+         concatenate back (to the left) with the second slice
'.*        join the with the dot character
            if the fractional part was zero, we only have the second slice
            (reversed integer part) and there is nothing to join
s          convert to string; this is the reversed result without the sign
W%         reverse back

À la fin, le signe moins (le cas échéant) et la chaîne finale sont automatiquement imprimés ensemble.

aditsu quitte parce que SE est MAL
la source
2

CJam, 50 octets

q~A1$z#\_0>K5?\z:E#@_s'-&oz*\md_sE'0e[W%isW%'.\+Q?

Il s'agit d'un programme complet qui lit à partir de STDIN. Essayez-le en ligne dans l' interpréteur CJam .

Vérifiez tous les cas de test à la fois.

Dennis
la source
Sur la base de votre commentaire, je suppose que CJam a une précision illimitée et vous l'avez utilisée ici? Est-il exact alors que cette réponse couvre n'importe quelle entrée, pas seulement un flottant 32 bits? De plus, pouvons-nous obtenir une explication de son fonctionnement?
edA-qa mort-ora-y
CJam a une précision illimitée pour les entiers, mais uniquement des flottants à double précision. Je multiplie par une puissance de 20 pour les exposants positifs et une puissance de 5 pour les exposants négatifs, le casting pour enfiler et insérer le point. J'ajouterai une explication détaillée dans quelques heures.
Dennis
Et oui, avec suffisamment de mémoire, cela devrait fonctionner pour n'importe quelle entrée.
Dennis
10 -2 semble avoir un zéro à la fin
aditsu quitte car SE est EVIL le
@aditsu: Ah oui, un zéro à la traîne pour chaque puissance de 2 ...
Dennis
2

GNU sed + dc, 65

Le score inclut +1 pour l' -roption de sed .

y/-/_/
s/.*/dc -e"C8k& 2r^*p"/e
s/\\\n//
s/0+$//
s/^(-?)\./\10./

J'ai été tenté de réclamer cette dcseule réponse C8k& 2r^*ppour un score de 10, mais j'ai dcquelques bizarreries de mise en forme:

  • le signe -ve est _au lieu de-
  • les longues lignes sont interrompues par des contre-obliques
  • les zéros de fin doivent être supprimés
  • 0 en tête pour |n| < 1doit être ajouté

Ainsi, l'expression dc est encapsulée et évaluée par sedpour prendre soin de ce qui précède.

Sortie de test:

$ echo "1 -2
17 -3
-123 11
17 50
23 -13
3 120
3 -50
-3 -50
8388608 127
1 -127" | sed -rf float.sed
0.25
2.125
-251904
19140298416324608
0.0028076171875
3987683987354747618711421180841033728
0.00000000000000266453525910037569701671600341796875
-0.00000000000000266453525910037569701671600341796875
1427247692705959881058285969449495136382746624
0.0000000000000000000000000000000000000058774717541114375398436826861112283890933277838604376075437585313920862972736358642578125
$ 
Traumatisme numérique
la source
Hmm, je pense que ce dcgenre de violation de ma règle sur l'utilisation d'une fonction de formatage standard.
edA-qa mort-ora-y
1
@ edA-qamort-ora-y Je me suis dit que l'utilisation de dcok était autorisée, étant donné que "l'arithmétique de précision fixe illimitée ou élevée est autorisée" . dcLa pcommande n'est pas une " fonction de formatage à virgule flottante" - c'est une fonction d'impression de précision arbitraire. Je mets la précision à 128 décimales ( C8k), ce qui, je pense, est plus que suffisant pour n'importe quel flotteur 32 bits.
Digital Trauma