2

Today I wrote a naive function that converts a float to a string by repeatedly modding by 10 and dividing by 10.

def to_string(x):
    r = ""
        while x >= 1.0:
            r = str(int(x%10)) + r
            x /= 10.0
    return r

I then tested my function against Python's built-in capability to convert a float to a string. Not too surprisingly, my function differs on large numbers.

>>> to_string(1e30)
'1000000000000000424684240284426'

>>> "%.f"%1e30
'1000000000000000019884624838656'

So, my question is: what computation do I have to do to get the digits that Python gets?

phuclv
  • 37,963
  • 15
  • 156
  • 475
2-complex
  • 333
  • 3
  • 11
  • 1
    [You've got a long read ahead of you.](https://github.com/python/cpython/blob/v3.6.4/Python/dtoa.c) – user2357112 Feb 10 '18 at 00:26
  • 3
    This is a good question, but it may be too broad for Stack Overflow. The conversion requires extended precision and techniques dependent on details of the floating-point format. – Eric Postpischil Feb 10 '18 at 03:15
  • 2
    On the other hand, it can be done with the same arithmetic we all learned in elementary school, if one puts enough effort into it. An array of small integers can be used to hold digits, the binary floating-point number can be put into the array using hexadecimal, and then the number can be converted to decimal by repeatedly dividing by ten and remember the remainders. So it would be elementary school long division using base-16 arithmetic. That method is slow compared to what is used in professional libraries, but it could be a good learning exercise. – Eric Postpischil Feb 10 '18 at 03:15
  • @Eric: I agree. It would be some work, but in the end, it should be possible using basic elementary school knowledge and some long and hard thinking. – Rudy Velthuis Feb 10 '18 at 14:33

1 Answers1

1

Here is a very simple solution. It is not intended to be efficient or to handle any values other than positive integers.

#!/usr/bin/python

import math

# This code represents a hexadecimal number using a list in which each item
# is a single hexadecimal digit (an integer from 0 to 15).

# Divide the base-16 digit-list in x by digit d.  This uses grade-school
# division, for a single-digit divisor.  It returns the quotient in a new
# digit-list and the remainder as a plain integer.
def Divide(x, d):

    # If the first digit is smaller than d, start an empty quotient with
    # a remainder being carried.
    if x[0] < d:
        q = []
        r = x[0]
    # Otherwise, start the quotient by dividing the first digit by d.
    else:
        q = [x[0] / d]
        r = x[0] % d

    # For the remaining digits, multiply the remainder by the base and
    # add the new digit.  Then divide by d, calculating a new digit of the
    # quotient and a new remainder to carry.
    for i in x[1:]:
        r = r*16 + i
        q.append(r/d)
        r = r % d

    return (q, r)

# Convert a positive integer floating-point value to decimal and print it.
def to_string(x):

    # Convert input to base 16.  This has no rounding errors since the
    # floating-point format uses base two, and 16 is a power of two.
    t= []
    while 0 < x:
        # Use remainder modulo 16 to calculate the next digit, then insert it.
        t.insert(0, int(x % 16))
        # Remove the digit from x.
        x = math.floor(x/16)

    # Start an empty output string.
    output = ""

    # Divide the number by 10 until it is zero (is an empty digit list).
    # Each time we divide, the remainder is a new digit of the answer.
    while t != []:
        (t, r) = Divide(t, 10)
        output = str(r) + output

    print output


to_string(1e30)
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312