Shop OBEX P1 Docs P2 Docs Learn Events
Unable to get floating point number (decimal value) from integer — Parallax Forums

Unable to get floating point number (decimal value) from integer

Hello everybody my name is Nicolas, I am extremely new to Spin language. I already setup a temperature sensor but I want to get decimal values from it. I do not know how to setup the floating point libraries, I have searched in the internet and OBEX and i know that i have to use FloatMath, Float32, Float32Full but I can not get any of them to work. A simple code like the following:
CON
    _clkmode = xtal1 + pll16x                           
    _xinfreq = 5_000_000


OBJ
pst     : "Parallax Serial Terminal"
fl     : "Float32"

PUB Main
fl.start
pst.start(57600)
pst.Str(String(pst#cs, pst#NL, pst#HM, "my float number is "))
pst.dec(fl.FFloat(1))


I would expect to get a 1.0 in the parallax serial terminal, but i always get 106535321. I am reading a temperature sensor from an MCP3208, and I want to convert the voltage level to a temperature value. So i need to calculate the following formula:
voltage level = (data * 3.3) / (1023)

And i want to be able to get decimal values I have tried the following code:

pst.Str(String(pst#NL, "temperature= "))
temp1 := adc.in(2)
pst.dec(f32.FFloat((temp1* 3.3)/1023))


And all i get is random big numbers, can somebody please help me? I've fallen and i cant get up!

Comments

  • ElectrodudeElectrodude Posts: 1,657
    edited 2016-07-30 22:24
    pst.dec prints integers, not floats. Floatmath.spin has methods to convert floats to strings, which you can then display with pst.str.

    Also, you can't use arithmetic operators (like +, -, *, and /) on floats - they only work on integers. You must use f32.fadd, f32.fmul, etc. instead.

    For example, the last line of the second piece of code you wrote should be:
    pst.str(fstr.floattostring(f32.fdiv(f32.fmul(f32.ffloat(temp1), 3.3),1023.0)))
    
    Note the 1023.0 to tell the compiler it should be a float and not an integer.

    That could be further simplified to the following, which saves a runtime divide:
    pst.str(fstr.floattostring(f32.fmul(f32.ffloat(temp1), constant(3.3 / 1023.0))))
    

    I'm not sure if you really need the constant() in there, or if the 1023 inside the constant() needs the decimal point - I never really understood the rules for floating point constants. Floating point math with arithmetic operators works at compile time, but at runtime you need to use f32 methods.
  • I'm not sure constant(3.3 / 1023.0) works like that on floats. Better just to do the math on a calculator and use .003225806452?

    -Phil
  • I'm 99% sure you actually can do that. I know, it's wierd, but you can do that. I have working code that does round(1.14*float(x)) at compile time and works just fine, but I've never tried actually doing constant(float_expr) at compile time.

    If you can't do that inside constant(), there's some place inside of CON blocks where you can.

    Just try it and see what works.
  • kwinnkwinn Posts: 8,697
    Another option is to avoid floating point altogether by doing the calculation with 32 bit integers. Faster and simpler.

    Multiply the temperature reading from the MCP by 3226 (( 3.3 / 1023 ) x 1,000,000 )
    Convert the result to decimal and place the decimal point where needed.
  • If you're just doing simple arithmetic, you're better off using integers.

    To place a decimal point within the number in the correct location (as suggested by kwinn) I use a method I call "DecPoint". Here's a link to this method.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2016-07-31 14:36
    Here are a couple more methods I use a lot when doing integer math on the Prop. These are methods Tracy Allen suggested when I was concerned about doing math with large numbers. These methods should prevent 32-bit overflow issues in many cases.
    PUB TtaMethodSigned(N, X, localD) | sign  ' return X*N/D
    
      sign := 1
      
      if N < 0
        -sign
        -N
      if X < 0
        -sign
        -X
      if localD < 0
        -sign
        -localD
        
      result := TtaMethod(N, X, localD) * sign
    
    PUB TtaMethod(N, X, localD)   ' return X*N/D where all numbers and result are positive =<2^31
      return (N / localD * X) + (binNormal(N//localD, localD, 31) ** (X*2))
    
    PUB BinNormal (y, x, b) : f                  ' calculate f = y/x * 2^b
    ' b is number of bits
    ' enter with y,x: {x > y, x < 2^31, y <= 2^31}
    ' exit with f: f/(2^b) =<  y/x =< (f+1) / (2^b)
    ' that is, f / 2^b is the closest appoximation to the original fraction for that b.
      repeat b
        y <<= 1
        f <<= 1
        if y => x    '
          y -= x
          f++
      if y << 1 => x    ' Round off. In some cases better without.
          f++
    

    I added the simple "TtaMethodSigned" method to make Tracy Allen's "TtaMethod" a bit more useful. If you know the three numbers you're using are all positive, you can skip the "TtaMethodSigned" method and simply call the "TtaMethod."
Sign In or Register to comment.