Shop OBEX P1 Docs P2 Docs Learn Events
Floating point math and strange results in the terminal — Parallax Forums

Floating point math and strange results in the terminal

turbosupraturbosupra Posts: 1,088
edited 2012-02-23 08:16 in Propeller 1
additionAnswer is: 2
subtractionAnswer is: -2
multiplicationAnswer is: 16
divisionAnswer is: 3
serialDataExample1 is: 1
serialDataExample2 is: 1

I'm unsure as to why I'm receiving "-2" as the result for the subtractionAnswer variable, and why I'm required to put pst.Str(fs.FloatToString(additionAnswer)) and pst.Str(fs.FloatToString(subtractionAnswer)) but then for division and multiplication I have to put pst.dec(multiplicationAnswer) and pst.dec(divisionAnswer) ? I'm also unsure as to why I cannot get the serialDataExample1 and serialDataExample2 to divide correctly? I can upload the objects later if someone would like them, just not from work because of the firewall.



CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
 

VAR

long numerator
long denominator
long constantMultiplier 
long additionAnswer
long subtractionAnswer
long multiplicationAnswer
long divisionAnswer

  

OBJ
pst : "Parallax Serial Terminal"
strings : "Strings"
f : "Float32"
fm : "FloatMath"
fs : "FloatString"



PUB Main

  {Addition: result = a + b
   Subtraction: result = a - b
   Multiplication: result = a * b
   Division: result = a / b}

  'numerator := 1640.0
  'denominator := 2.0
  'constantMultiplier := 1.221

  pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
  pst.Clear 
  f.start

  pst.Str(String("Start" ))
  pst.Str(String(pst#NL))

 repeat

                             'x := f.FAdd(x, y) is correct - from the propeller floating point math pdf file

     additionAnswer := f.FAdd(2.0, 4) 
     subtractionAnswer := f.FSub(4, 2.0)
     multiplicationAnswer := f.FMul(8, 2.0) 
     divisionAnswer := f.Fdiv(6, 2.0)
     serialDataExample1 := (f.FMul(820, 0.001221))
     serialDataExample2 := ((f.FMul(1638, 1.221)/1000)) 
      
     pst.Str(String("additionAnswer is: " ))
     pst.Str(fs.FloatToString(additionAnswer))
     pst.Str(String(pst#NL))

     pst.Str(String("subtractionAnswer is: " ))
     pst.Str(fs.FloatToString(subtractionAnswer))
     pst.Str(String(pst#NL))

     pst.Str(String("multiplicationAnswer is: " ))
     pst.dec(multiplicationAnswer)
     pst.Str(String(pst#NL))

     pst.Str(String("divisionAnswer is: " ))
     pst.dec(divisionAnswer)
     pst.Str(String(pst#NL))

     pst.Str(String("serialDataExample1 is: " ))
     pst.Dec((serialDataExample1))
     pst.Str(String(pst#NL))

     pst.Str(String("serialDataExample2 is: " ))
     pst.Dec((serialDataExample2))
     pst.Str(String(pst#NL))

    WaitCnt((clkfreq) + cnt)
 

Comments

  • ElectricAyeElectricAye Posts: 4,561
    edited 2012-02-22 11:59
    I can't remember for sure about the use of decimal points in this object, but should

    divisionAnswer := f.Fdiv(6, 2.0)

    be written as divisionAnswer := f.Fdiv(6.0, 2.0)

    ????
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 12:03
    ElectricAye is right. You need ".0" on all the constants you're using as floating point.

    Beside the "6" just mentioned, I also see a "4" without a ".0" on it. (And a 1638, 820 etc.)
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 12:04
    I bet
    serialDataExample2 := ((f.FMul(1638, 1.221)/1000)) 
    
    doesn't do what you want it to. You can't mix floating point and interger math like that.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-02-22 12:21
    Thanks! You both were right, the only issue now with the code below is that it truncates all values after the decimal point, what should I do to obtain 1 decimal place?
    I can't remember for sure about the use of decimal points in this object, but should

    divisionAnswer := f.Fdiv(6, 2.0)

    be written as divisionAnswer := f.Fdiv(6.0, 2.0)

    ????
    Duane Degn wrote: »
    ElectricAye is right. You need ".0" on all the constants you're using as floating point.

    Beside the "6" just mentioned, I also see a "4" without a ".0" on it. (And a 1638, 820 etc.)
    Duane Degn wrote: »
    I bet
    serialDataExample2 := ((f.FMul(1638, 1.221)/1000)) 
    
    doesn't do what you want it to. You can't mix floating point and interger math like that.


    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
     
    
    VAR
    
    long numerator
    long denominator
    long constantMultiplier 
    long additionAnswer
    long subtractionAnswer
    long multiplicationAnswer
    long divisionAnswer
    long serialDataExample1
    long serialDataExample2
    
      
    
    OBJ
    pst : "Parallax Serial Terminal"
    strings : "Strings"
    f : "Float32"
    fm : "FloatMath"
    fs : "FloatString"
    
    
    
    PUB Main
    
      {Addition: result = a + b
       Subtraction: result = a - b
       Multiplication: result = a * b
       Division: result = a / b}
    
      'numerator := 1640.0
      'denominator := 2.0
      'constantMultiplier := 1.221
      
    
      pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
      pst.Clear 
      f.start
    
      pst.Str(String("Start" ))
      pst.Str(String(pst#NL))
    
     repeat
    
                                 'x := f.FAdd(x, y) is correct - from the propeller floating point math pdf file
    
         additionAnswer := f.FAdd(2.0, 4.0) 
         subtractionAnswer := f.FSub(4.0, 2.0)
         multiplicationAnswer := f.FMul(8.0, 2.0) 
         divisionAnswer := f.Fdiv(6.0, 2.0)
         serialDataExample1 := (f.FMul(820, 0.001221))
         serialDataExample2 := ((f.FMul(1638, 0.001221))) 
          
         pst.Str(String("additionAnswer is: " ))
         pst.Str(fs.FloatToString(additionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("subtractionAnswer is: " ))
         pst.Str(fs.FloatToString(subtractionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("multiplicationAnswer is: " ))
         pst.Str(fs.FloatToString(multiplicationAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("divisionAnswer is: " ))
         pst.Str(fs.FloatToString(divisionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("serialDataExample1 is: " ))
         pst.Dec((serialDataExample1))
         pst.Str(String(pst#NL))
    
         'pst.dec(serialDataExample2)
         'pst.Str(String(pst#NL))
         pst.Str(String("serialDataExample2 is: " ))
         pst.Dec((serialDataExample2))
         pst.Str(String(pst#NL))
    
        WaitCnt((clkfreq) + cnt)
    
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 12:38
    Try using the SetPrecision method of the FloatString object.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-02-22 12:58
    Hi Duane,

    I put this line right under f.start

    fs.SetPrecision(4)

    and still nothing. I tried f.FRound in a few places as well without luck? Am I putting the fs.SetPrecision(4) in the correct location? If not, can you quote my code and show me where please?

    Duane Degn wrote: »
    Try using the SetPrecision method of the FloatString object.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 13:29
    One of the SHT11 humidity object has some sort of floating point formatting.

    I'm usually not worried about the formatting of my floating point projects.

    You could use the "round" method and then output with a method like this:
    PUB DecPoint(value, denominator) 
      if value < 0
        tx("-")
        -value
          
      if value => denominator
        result := value / denominator
        dec(result)
        value //= denominator     
      else    
        tx("0")
      tx(".")  
      repeat while denominator > 1
        denominator /= 10
        if value => denominator
          result := value / denominator
          dec(result)
          value //= denominator
        else
          tx("0")
          
    
    

    You could add the method to your serial object. Just make sure and change all the "tx" calls to what ever the method is called in your serial object. For PST, all the tx calls will need to be changed to char calls.

    So if you have a variable "x" with a number you want to display to one digit past the decimal, do this.
    x := F.FMul(x, 10.0)
      x := F.FRound(x)
      Pst.DecPoint(x, 10)
    

    This assumes you've added the DecPoint method to PST.

    I think finding a floating point formatting method would be less awkward though.

    Oh, lose the "Float32" and "FloatMath". Those objects are so last decade! F32 is the way to go. It's faster and fits in one cog. You shouldn't need to modify your code to use it.

    The latest version of F32 is here. The OBEX version has a bug.

    Edit (July 12, 2012): I fixed a bug the DecPoint method above. Thank you Gunstar1 for pointing it out.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-02-22 14:10
    Thank you.

    I don't know why, but I cannot get this to work, it seems like it should be a very simple thing too. I did as you suggested with modifying the pst object, without luck and I cannot for the life of me get it to round up??? Below is the current status, I appreciate you sticking with me on this.

    1
    1
    serialDataExample2 is: 1
    0.0


    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
     
    
    VAR
    
    long numerator
    long denominator
    long constantMultiplier 
    long additionAnswer
    long subtractionAnswer
    long multiplicationAnswer
    long divisionAnswer
    long serialDataExample1
    long serialDataExample2
    long serialDataExample1b
    long serialDataExample2b
    
      
    
    OBJ
    pst : "Parallax Serial Terminal"
    strings : "Strings"
    'f : "Float32"
    f : "F32"
    fm : "FloatMath"
    fs : "FloatString"
    
    
    
    PUB Main
    
      {Addition: result = a + b
       Subtraction: result = a - b
       Multiplication: result = a * b
       Division: result = a / b}
    
      'numerator := 1640.0
      'denominator := 2.0
      'constantMultiplier := 1.221
      
    
      pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
      pst.Clear 
      f.start
      fs.SetPrecision(4)
      
      pst.Str(String("Start" ))
      pst.Str(String(pst#NL))
    
     repeat
    
                                 'x := f.FAdd(x, y) is correct - from the propeller floating point math pdf file
         
         serialDataExample1 := (f.FMul(820, 0.001221))
         serialDataExample2 := (f.FMul(1638, 0.001221))
         pst.Dec((serialDataExample2))
         pst.Str(String(pst#NL))
         serialDataExample2b := f.FRound(f.FFloat(serialDataExample2))
         pst.Dec((serialDataExample2b))
         pst.Str(String(pst#NL))
        
         pst.Str(String("serialDataExample2 is: " ))
         pst.Dec(f.FRound(f.FFloat(serialDataExample2)))
         pst.Str(String(pst#NL))
         pst.DecPoint((serialDataExample2), 10)
         pst.Str(String(pst#NL))
         pst.Str(String(pst#NL))
    
          'serialDataExample2b := f.FFloat(serialDataExample2)
    
         'pst.dec(serialDataExample2)
         'pst.Str(String(pst#NL))
         
        WaitCnt((clkfreq) + cnt)
        
    
    

    Duane Degn wrote: »
    One of the SHT11 humidity object has some sort of floating point formatting.

    I'm usually not worried about the formatting of my floating point projects.

    You could use the "round" method and then output with a method like this:
    PUB DecPoint(value, denominator) 
      if value < 0
        tx("-")
        -value
          
      if value > denominator
        result := value / denominator
        dec(result)
        value //= denominator     
      else    
        tx("0")
      tx(".")  
      repeat while denominator > 1
        denominator /= 10
        if value > denominator
          result := value / denominator
          dec(result)
          value //= denominator
        else
          tx("0")
          
    
    

    You could add the method to your serial object. Just make sure and change all the "tx" calls to what ever the method is called in your serial object. For PST, all the tx calls will need to be changed to char calls.

    So if you have a variable "x" with a number you want to display to one digit past the decimal, do this.
    x := F.FMul(x, 10.0)
      x := F.FRound(x)
      Pst.DecPoint(x, 10)
    

    The below was added to pst.spin
    PUB DecPoint(value, denominator) 
      if value < 0
        Char("-")
        -value
          
      if value > denominator
        result := value / denominator
        dec(result)
        value //= denominator     
      else    
        Char("0")
      Char(".")  
      repeat while denominator > 1
        denominator /= 10
        if value > denominator
          result := value / denominator
          dec(result)
          value //= denominator
        else
          Char("0")
      
    
    

    This assumes you've added the DecPoint method to PST.

    I think finding a floating point formatting method would be less awkward though.

    Oh, lose the "Float32" and "FloatMath". Those objects are so last decade! F32 is the way to go. It's faster and fits in one cog. You shouldn't need to modify your code to use it.

    The latest version of F32 is here. The OBEX version has a bug.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 14:13
    You still have numbers you're treating as floating point that don't end with ".0". Did you multply the floating point number by 10.0 before rounding?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 14:14
    Duane Degn wrote: »
    (And a 1638, 820 etc.)
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 14:22
    Floating point is useful for trig and log functions but if your just using multiply and divide you can use pseudo real numbers.

    Instead of "0.001221" use 1221 and just remember it has been multiplied by 1,000,000 and compensate later when you do other calculations on it.

    You would use DecPoint to display it with 1,000,000 as the denominator.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-02-22 14:28
    I found the FloatString object with the format method. Watch out, it has the same name as the other object.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-02-22 14:46
    Ok, that was it. I'm going to have to force my ADC values to a float I guess with the f.FFloat method? Thanks for pointing that out. I can get a rounded version and a decimal version now ... excellent! Thanks again. I'll post the code in case this thread turns up in someones search.
    additionAnswer is: 6
    subtractionAnswer is: 2
    multiplicationAnswer is: 16
    divisionAnswer is: 3
    serialDataExample1 is: 1065363450
    1
    serialDataExample2b is: 2
    serialDataExample2 is: 2
    1987788
    1.9

    repeat
    
                                 'x := f.FAdd(x, y) is correct - from the propeller floating point math pdf file
         
         additionAnswer := f.FAdd(2.0, 4.0) 
         subtractionAnswer := f.FSub(4.0, 2.0)
         multiplicationAnswer := f.FMul(8.0, 2.0) 
         divisionAnswer := f.Fdiv(6.0, 2.0)
         serialDataExample1 := (f.FMul(820.0, 0.001221))
         serialDataExample2 := (f.FMul(1628.0, 0.001221))
         serialDataExample3 := (f.FMul(1628.0, 1221))
         'serialDataExample1 := (f.FMul(f.FFloat(820), 0.001221))
         'serialDataExample2 := (f.FMul(f.FFloat(1628), 0.001221))
         'serialDataExample3 := (f.FMul(f.FFloat(1628), 1221))
         pst.Dec(f.FTrunc(serialDataExample2))
         pst.Str(String(pst#NL))
         serialDataExample2b := f.FRound((serialDataExample2))
         pst.Str(String("serialDataExample2b is: " ))
         pst.Dec((serialDataExample2b))
         pst.Str(String(pst#NL))
        
         pst.Str(String("serialDataExample2 is: " ))
         pst.Dec(f.FRound(serialDataExample2))
         pst.Str(String(pst#NL))
         pst.Dec(serialDataExample3)
         pst.Str(String(pst#NL))
         pst.DecPoint((serialDataExample3/100000), 10)
         pst.Str(String(pst#NL))
         pst.Str(String(pst#NL))
    
        pst.Str(String("additionAnswer is: " ))
         pst.Str(fs.FloatToString(additionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("subtractionAnswer is: " ))
         pst.Str(fs.FloatToString(subtractionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("multiplicationAnswer is: " ))
         pst.Str(fs.FloatToString(multiplicationAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("divisionAnswer is: " ))
         pst.Str(fs.FloatToString(divisionAnswer))
         pst.Str(String(pst#NL))
    
         pst.Str(String("serialDataExample1 is: " ))
         pst.Dec((serialDataExample1))
         pst.Str(String(pst#NL)) 
    
    
       WaitCnt((clkfreq) + cnt)
    
    

    Duane Degn wrote: »
    Floating point is useful for trig and log functions but if your just using multiply and divide you can use pseudo real numbers.

    Instead of "0.001221" use 1221 and just remember it has been multiplied by 1,000,000 and compensate later when you do other calculations on it.

    You would use DecPoint to display it with 1,000,000 as the denominator.
  • Paul K.Paul K. Posts: 150
    edited 2012-02-22 21:35
    I had the same problem. I use mpc3208 a/d's and I float them all. You have to float the adc values if you use it in a floating equation. Or use the adc value in a non floating equation. Or trunc the other value before using the adc value in a non floating equation.

    F.ffloat method is correct. You can throw in to a equation like. Sum := f.fadd(f.ffloat(adc1),2.0) or just float them as you read the value in.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-02-23 08:16
    Thanks Paul.

    Do you have any other 3208 interface tips, so I can save myself the headache? :)

    I'm hoping this post will come up in a search to save future users the headache of banging their head through this process like I did. It's a lot easier to work backwards from a working set of code, then to work through all of the issues to get to that working set of code.
Sign In or Register to comment.