SyntaxError: decimal numbers not supported

Questions and discussion about The WiPy 1.0 board and CC3200 boards.
Target audience: Users with a WiPy 1.0 or CC3200 board.
User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: SyntaxError: decimal numbers not supported

Post by pythoncoder » Mon Mar 07, 2016 7:10 am

@danicampora It would be good to have a definitive answer on this one. Will the WiPy ever be capable of supporting basic float arithmetic? I don't mind waiting as long as it takes while you figure it out, but it would be good to know if it's a problem waiting to be fixed or something which is simply not practicable.

My personal view is that if you can't write a = b/c it isn't Python.
Peter Hinch
Index to my micropython libraries.

jobbyworld
Posts: 2
Joined: Tue Jun 30, 2015 8:25 pm

Re: SyntaxError: decimal numbers not supported

Post by jobbyworld » Sat Mar 12, 2016 10:53 pm

Should be great to have floating point enable for testing.
I have a pyb and wipy,

wifi apmode is great
sleep mode is cool
But without floating point, can't compute altitude with barometric and temperature,
Can't compute gps data...

So i'm using pyboard until i receive my lopy :-)

Thanks to all micropython, creator and contributor.

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: SyntaxError: decimal numbers not supported

Post by danicampora » Sun Mar 13, 2016 10:43 am

Hi guys,

I am sorry to say that floating point is not coming to the WiPy, it takes too much space leaving very little ram available.

Cheers,
Daniel

photoacoustic
Posts: 24
Joined: Mon Apr 27, 2015 8:25 am

Re: SyntaxError: decimal numbers not supported

Post by photoacoustic » Sun Mar 13, 2016 6:46 pm

@danicampora
This is really a bad new!
How to teach micrpython and say hey don't use a/b ...?
Very bad new!
I hope Lopy will not have the same story!
Best regards

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: SyntaxError: decimal numbers not supported

Post by danicampora » Sun Mar 13, 2016 6:48 pm

Hi,

You can use a//b to make it a floor divide.

Cheers,
Daniel

photoacoustic
Posts: 24
Joined: Mon Apr 27, 2015 8:25 am

Re: SyntaxError: decimal numbers not supported

Post by photoacoustic » Sun Mar 13, 2016 6:54 pm

Yes.
Thanks
I will try.
Some examples of usage are welcome. On Pycom it seems that some examples are coming..

User avatar
marfis
Posts: 215
Joined: Fri Oct 31, 2014 10:29 am
Location: Zurich / Switzerland

Re: SyntaxError: decimal numbers not supported

Post by marfis » Wed Mar 16, 2016 2:30 pm

@jobbyworld: Most likely you can use your sensors with fixed point, see for example
https://github.com/micropython/Micropython/pull/1843 and other drivers which implement both fixed point and floating point support. Most of the time the only difference is one line of code.

In the link above was also a question of Damien if it made sense to support fixed point support for sensors.

It would be good if this can be clarified in the future, especially if more sensors drivers should find their way to the main repo.

jgmdavies
Posts: 57
Joined: Tue Aug 09, 2016 2:39 pm

Re: SyntaxError: decimal numbers not supported

Post by jgmdavies » Fri Aug 26, 2016 3:24 pm

I've written a simple WiPy float package if anyone wants to try it out - please see http://forum.micropython.org/viewtopic. ... 205#p13205

It doesn't have the syntactic nicety of x = y / z, but you can achieve something similar, e.g.

Code: Select all

x = Float(1)
y = Float(3)
z = Float.divide(x, y)
print(x)
Jim

jgmdavies
Posts: 57
Joined: Tue Aug 09, 2016 2:39 pm

Re: SyntaxError: decimal numbers not supported

Post by jgmdavies » Sat Aug 27, 2016 10:39 am

I've added more operator overloads to WiPyFloat (see above), so that this sort of thing now works:

Code: Select all

x = Float(1) / Float(3)
print(x)

Code: Select all

x = Float("1.45") / Float("3.78")
print(x)
It's just under 6 Kb at the moment, as measured by gc.mem_free().

Jim

WiPyFloat.py

Code: Select all

# WiPyFloat.py
# Last modified: 27 Aug 2016

# J.G.Davies, Jacobus Systems Ltd., Brighton & Hove, UK.
# This code is hereby released as Public Domain.  I would appreciate an acknowledgement if you find it useful.


class Float():

    mantissa = 0
    exponent = 0


    def __init__(self, f=None):
        if f:
            if (type(f).__name__ == "Float"):
                self.mantissa = f.mantissa
                self.exponent = f.exponent
            elif (type(f).__name__ == "int"):
                self.mantissa = int(f)
                self.exponent = 0
            elif (type(f).__name__ == "str"):
                self.load(str(f))

            self.normalise()

        return

    # Operator overloads.

    def __abs__(self):
        result = Float(self)
        result.mantissa = abs(result.mantissa)
        return result

    def __add__(self, other):
        return Float.add(self, other)

    def __eq__(self, other):
        self.normalise()
        other.normalise()
        return (self.mantissa == other.mantissa) and (self.exponent == other.exponent)

    def __mul__(self, other):
        return Float.multiply(self, other)

    def __neg__(self):
        result = Float(self)
        result.mantissa = -result.mantissa
        return result

    def __pos__(self):
        return Float(self)

    def __str__(self):
        return self.str()

    def __sub__(self, other):
        return Float.subtract(self, other)

    def __truediv__(self, other):
        return Float.divide(self, other)


    # Static methods.

    @staticmethod
    def add(f1, f2):
        # Return a new Float holding (f1 + f2).
        result = Float(f1)
        result.add_float(f2)
        return result

    @staticmethod
    def divide(f1, f2):
        # Return a new Float holding (f1 / f2).
        result = Float(f1)
        result.divide_float(f2)
        return result

    @staticmethod
    def multiply(f1, f2):
        # Return a new Float holding (f1 * f2).
        result = Float(f1)
        result.multiply_float(f2)
        return result

    @staticmethod
    def subtract(f1, f2):
        # Return a new Float holding (f1 - f2).
        result = Float(f1)
        result.subtract_float(f2)
        return result


    # Methods.
    def add_float(self, f, add=True):
        # Add Float 'f' to this Float.

        # Align the exponents.
        self_mantissa = self.mantissa
        self_exponent = self.exponent
        f_mantissa = f.mantissa
        f_exponent = f.exponent

        if (f_exponent < self_exponent):
            shift = self_exponent - f_exponent
            self_mantissa *= 10 ** shift
            self_exponent -= shift
        elif (f_exponent > self_exponent):
            shift = f_exponent - self_exponent
            f_mantissa *= 10 ** shift
            f_exponent -= shift

        if add:
            self.mantissa = self_mantissa + f_mantissa
        else:
            self.mantissa = self_mantissa - f_mantissa

        self.exponent = self_exponent
        self.normalise()

        return self


    def debug(self):
        s = "Float: {0}, {1}".format(self.mantissa, self.exponent)
        return s


    def divide_float(self, f):
        # Divide this Float by 'f'.
        self.mantissa *= 100000000
        self.exponent -= 8

        self.mantissa //= f.mantissa
        self.exponent -= f.exponent
        self.normalise()

        return self


    def int(self):
        result = 0
        return result


    def load(self, s):
        s = s.strip().lower()
        pos = True

        if (s[0] == "+"):
            s = s[1:]
        elif (s[0] == "-"):
            s = s[1:]
            pos = False

        if "e" in s:
            return self.load_scientific(s, pos)

        if "." in s:
            whole, decimal = s.split(".")

            if not decimal:
                # There is no decimal part.
                # TODO: if 'whole' ends in zeros, could scale the number and set self.exponent.
                # This would help keep 'mantissa' a simple 31-bit int on the WiPy.
                self.mantissa = int(whole)
                if not pos: self.mantissa = -self.mantissa
                self.exponent = 0
                self.normalise()
                return True

            # There is a decimal part.
            if whole and (int(whole) == 0):
                whole = None

            if not whole:
                # There is no whole part.
                value, nleading = self.parse_decimal(decimal)
                self.mantissa = int(value)
                if not pos: self.mantissa = -self.mantissa
                self.exponent = -nleading - len(value)
                self.normalise()
                return True

            # There is a whole part and a decimal part.
            whole = whole.lstrip("0")
            decimal = decimal.rstrip('0')
            self.mantissa = int(whole + decimal)
            if not pos: self.mantissa = -self.mantissa
            self.exponent = -len(str(decimal))
            self.normalise()

        else:
            # TODO: if 'whole' ends in zeros, could scale the number and set self.exponent.
            # This would help keep 'mantissa' a simple 31-bit int on the WiPy.
            self.mantissa = int(s)
            if not pos: self.mantissa = -self.mantissa
            self.exponent = 0
            self.normalise()

            return True

        return True


    def multiply_float(self, f):
        # Multiply this Float by 'f'.
        self.mantissa *= f.mantissa
        self.exponent += f.exponent
        self.normalise()

        return self


    def normalise(self):
        # Normalise where possible.
        if (self.mantissa != 0):
            s = str(self.mantissa)
            stripped = s.rstrip("0")
            diff = len(s) - len(stripped)

            if (diff > 0):
                self.mantissa = int(stripped)
                self.exponent += diff

        return True


    def str(self, format="F"):
        if ("E" in format):
            return self.str_scientific()

        # Use format "F".
        pos = (self.mantissa >= 0)
        result = str(abs(self.mantissa))

        if (self.exponent > 0):
            result += "0" * self.exponent
        elif (self.exponent < 0):
            if (-self.exponent < len(result)):
                cut = len(result) + self.exponent
                result = result[:cut] + "." + result[cut:]
            else:
                n_zeros = -self.exponent - len(result)
                result = "0." + ("0" * n_zeros) + result

        if not pos: result = "-" + result

        return result


    def subtract_float(self, f):
        # Subtract Float 'f' from this Float.
        return self.add_float(f, False)



    # Helper methods.

    def load_scientific(self, s, pos):
        mant, exp = s.split("e")
        self.load(mant)
        self.exponent += int(exp)
        self.normalise()

        return False


    def parse_decimal(self, s):
        nleading = 0

        for c in s:
            if (c != "0"): break
            nleading += 1

        if (nleading == 0):
            value = s
        else:
            value = s[nleading:]

        return value, nleading


    def str_scientific(self):
        pos = (self.mantissa >= 0)
        result = str(abs(self.mantissa))
        len_mantissa = len(result)

        if (len(result) > 1):
            result = result[:1] + "." + result[1:]
            result = result.rstrip("0")
            result = result.rstrip(".")

        result += "e" + str(self.exponent + len_mantissa - 1)

        if not pos: result = "-" + result

        return result


#import Float_tests

Float_tests.py

Code: Select all

# Float_tests.py
# Last modified: 27 Aug 2016

# J.G.Davies, Jacobus Systems Ltd., Brighton & Hove, UK.
# This code is hereby released as Public Domain.  I would appreciate an acknowledgement if you find it useful.

from WiPyFloat import Float


def test1():
    # 'load' and 'str' methods.
    print("test1 - load / str")
    f1 = Float()

    f1.load("1.3")
    print(PassFail(f1.str() == "1.3"), "1.3 ->", f1, f1.str("E"))

    f1.load("-1.3")
    print(PassFail(f1.str() == "-1.3"), "-1.3 ->", f1, f1.str("E"))

    f1.load("2000.05")
    print(PassFail(f1.str() == "2000.05"), "2000.05 ->", f1, f1.str("E"))

    f1.load("0.01")
    print(PassFail(f1.str() == "0.01"), "0.01 ->", f1, f1.str("E"))

    f1.load("0.0123")
    print(PassFail(f1.str() == "0.0123"), "0.0123 ->", f1, f1.str("E"))

    f1.load("0.00123")
    print(PassFail(f1.str() == "0.00123"), "0.00123 ->", f1, f1.str("E"))

    f1.load("1.23e-3")
    print(PassFail(f1.str() == "0.00123"), "1.23e-3 ->", f1, f1.str("E"))

    f1.load("1.23e6")
    print(PassFail(f1.str() == "1230000"), "1.23e6 ->", f1, f1.str("E"))

    f1.load("5e6")
    print(PassFail(f1.str() == "5000000"), "5e6 ->", f1, f1.str("E"))

    print("")

    return True


def test2():
    # Addition.
    print("test2 - Addition")
    f1 = Float()
    f2 = Float()

    f1.load("2000.05")
    f2.load("0.001")
    f3 = Float.add(f1, f2)
    print(PassFail(f3.str() == "2000.051"), f1, "+", f2, "->", f3, f3.str("E"))

    f1.load("0.1")
    f2.load("0.2")
    f3 = Float.add(f1, f2)
    print(PassFail(f3.str() == "0.3"), f1, "+", f2, "->", f3, f3.str("E"))

    f1.load("500")
    f2.load("600")
    f3 = Float.add(f1, f2)
    print(PassFail(f3.str() == "1100"), f1, "+", f2, "->", f3, f3.str("E"))

    f1.load("500")
    f2.load("-600")
    f3 = Float.add(f1, f2)
    print(PassFail(f3.str() == "-100"), f1, "+", f2, "->", f3, f3.str("E"))

    f1.load("-500")
    f2.load("600")
    f3 = Float.add(f1, f2)
    print(PassFail(f3.str() == "100"), f1, "+", f2, "->", f3, f3.str("E"))

    print("")

    return True


def test3():
    # Subtraction.
    print("test3 - Subtraction")
    f1 = Float()
    f2 = Float()

    f1.load("2000.05")
    f2.load("0.001")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "2000.049"), f1, "-", f2, "->", f3, f3.str("E"))

    f1.load("0.1")
    f2.load("0.2")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "-0.1"), f1, "-", f2, "->", f3, f3.str("E"))

    f1.load("10")
    f2.load("0.6667")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "9.3333"), f1, "-", f2, "->", f3, f3.str("E"))

    f1.load("500")
    f2.load("600")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "-100"), f1, "-", f2, "->", f3, f3.str("E"))

    f1.load("500")
    f2.load("-600")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "1100"), f1, "-", f2, "->", f3, f3.str("E"))

    f1.load("-500")
    f2.load("600")
    f3 = Float.subtract(f1, f2)
    print(PassFail(f3.str() == "-1100"), f1, "-", f2, "->", f3, f3.str("E"))

    print("")

    return True


def test4():
    # Multiplication.
    print("test4 - Multiplication")
    f1 = Float()
    f2 = Float()

    f1.load("5")
    f2.load("6")
    f3 = Float.multiply(f1, f2)
    print(PassFail(f3.str() == "30"), f1, "*", f2, "->", f3, f3.str("E"))

    f1.load("500")
    f2.load("600")
    f3 = Float.multiply(f1, f2)
    print(PassFail(f3.str() == "300000"), f1, "*", f2, "->", f3, f3.str("E"))

    f1.load("5e3")
    f2.load("6e3")
    f3 = Float.multiply(f1, f2)
    print(PassFail(f3.str() == "30000000"), f1, "*", f2, "->", f3, f3.str("E"))

    f1.load("5e6")
    f2.load("6e6")
    f3 = Float.multiply(f1, f2)
    print(PassFail(f3.str() == "30000000000000"), f1, "*", f2, "->", f3, f3.str("E"))

    print("")

    return True


def test5():
    # Division.
    print("test5 - Division")
    f1 = Float()
    f2 = Float()

    f1.load("1")
    f2.load("3")
    f3 = Float.divide(f1, f2)
    print(PassFail(f3.str()[:7] == "0.33333"), f1, "/", f2, "->", f3, f3.str("E"), f3.debug())

    f1.load("5")
    f2.load("6")
    f3 = Float.divide(f1, f2)
    print(PassFail(f3.str()[:7] == "0.83333"), f1, "/", f2, "->", f3, f3.str("E"), f3.debug())

    f1.load("500")
    f2.load("600")
    f3 = Float.divide(f1, f2)
    print(PassFail(f3.str()[:7] == "0.83333"), f1, "/", f2, "->", f3, f3.str("E"), f3.debug())

    f1.load("5e3")
    f2.load("6e3")
    f3 = Float.divide(f1, f2)
    print(PassFail(f3.str()[:7] == "0.83333"), f1, "/", f2, "->", f3, f3.str("E"), f3.debug())

    f1.load("5e6")
    f2.load("6e6")
    f3 = Float.divide(f1, f2)
    print(PassFail(f3.str()[:7] == "0.83333"), f1, "/", f2, "->", f3, f3.str("E"), f3.debug())

    print("")

    return True


def test6():
    # Object creation options.
    print("test6 - Object creation")
    f1 = Float()
    print(PassFail(f1.str() == "0"), f1, f1.debug())

    f1 = Float(123)
    print(PassFail(f1.str() == "123"), f1, f1.debug())

    f1 = Float("3.1416")
    print(PassFail(f1.str() == "3.1416"), f1, f1.debug())

    f2 = Float(f1)
    print(PassFail(f1.str() == "3.1416"), f2, f2.debug())

    print("")

    return True


def test7():
    # Equality / Inequality operator overloads.
    print("test7 - Equality / Inequality operator overloads")
    f1 = Float(123)
    f2 = Float("123")
    f3 = Float("123.0001")

    print(PassFail(f1 == f2), "(", f1, "==", f2, ") is", f1 == f2)
    print(PassFail(f1 != f3), "(", f1, "==", f3, ") is", f1 == f3)
    print(PassFail(f1 == f2), "(", f1, "!=", f2, ") is", f1 != f2)
    print(PassFail(f1 != f3), "(", f1, "!=", f3, ") is", f1 != f3)

    print("")

    return True


def test8():
    # test8 - Arithmetic operator overloads.
    print("test8 - Arithmetic operator overloads")
    f1 = Float("1.8")
    f2 = Float("3.7")

    f3 = f1 + f2
    print(PassFail(f3.str() == "5.5"), f1, "+", f2, "->", f3, f3.str("E"))

    f3 = f1 - f2
    print(PassFail(f3.str() == "-1.9"), f1, "-", f2, "->", f3, f3.str("E"))

    f3 = f1 * f2
    print(PassFail(f3.str() == "6.66"), f1, "*", f2, "->", f3, f3.str("E"))

    f3 = f1 / f2
    print(PassFail(f3.str()[:8] == "0.486486"), f1, "/", f2, "->", f3, f3.str("E"))

    return True


def PassFail(cond):
    return ("PASS" if cond else "FAIL") + ": "


test1()
test2()
test3()
test4()
test5()
test6()
test7()
test8()

MiPy
Posts: 3
Joined: Sat Sep 12, 2015 3:22 pm

Re: SyntaxError: decimal numbers not supported

Post by MiPy » Sat Aug 27, 2016 10:52 am

Looks nice! I'm going to try it out in a couple of days.

Post Reply