Shop OBEX P1 Docs P2 Docs Learn Events
Floating point comparsion operators — Parallax Forums

Floating point comparsion operators

Has anyone had issues with the floating point <. and >. spin operators?
I am seeing these give unexpected results with pnut 39/40 and propeller tool 2.9.3 but flexprop 6.5 is giving the result I would expect.
The test code is at https://github.com/timmmoore/Swervebot/blob/master/test/test.spin2
for example

if test1 <. test2
     debug("if test1 <. test2")
else
     debug("else test1 <. test2")

will print the else when test1 = 1.0 and test2 = 2.0.
I think the problem is in the spin_interpreter, in particular this code in frel_

                bitl    w,#31           wcz     'make left-side comparable
                cmp     w,##$7F800001   wc      'NaN?
        if_z    neg     w                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm

                bitl    x,#31           wcz     'make right-side comparable
        if_c    cmp     x,##$7F800001   wc      'NaN?
        if_z    neg     x                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm

I believe the carry used in the 2nd cmp, should be from the previous cmp but it is overwritten by the 2nd bitl.
When I change it not to do this I get the expected result.

Tim

Comments

  • I don't use Spin but I think changing one line fixes this issue:

    frel_           popa    w                       'pop left-side float
    
                    bitl    w,#31           wcz     'make left-side comparable
                    cmp     w,##$7F800001   wc      'NaN?
            if_z    neg     w                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_c    bitl    x,#31           wcz     'make right-side comparable ***CHANGED***
            if_c    cmp     x,##$7F800001   wc      'NaN?
            if_z    neg     x                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_nc   skip    #%11111                 'if either NaN, return false
    
                    cmps    w,x             wcz     'do comparison
            if_z    mov     y,#%1000                'equal?
            if_nz   mov     y,#%0100                'above?
            if_c    mov     y,#%0010                'below?
                    test    y,pa            wc      'test mask
    
            _ret_   muxc    x,_FFFFFFFF             'return boolean
    
  • cgraceycgracey Posts: 14,151

    Thanks for catching this!

    I see I had to use WCZ after BITL, in order to affect Z, so the C result was just incidental and gets ignored. The next instruction meaningfully affects C, but then there's some error in my logic. TonyB probably nailed it, but I need to get on my computer and work through this.

    I will have this fixed in several hours.

  • Thanks, The test file on github has several tests cases though not exhausive, but does check <. >. <=. and >=. and the test cases try the obvious cases, i.e., +ve, -ve, true and false.
    It tests a different fix as well but it adds 1 instruction so TonyB fix is better,

  • I just tried TonyB code with my test cases and it didnt' give the right answer.

  • @Timmoore said:
    I just tried TonyB code with my test cases and it didnt' give the right answer.

    How about this?

    frel_           popa    w                       'pop left-side float
    
                    bitl    w,#31           wcz     'make left-side comparable
                    cmp     w,##$7F800001   wc      'NaN?
            if_z    neg     w                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_nc   skip    #%111111111             'if NaN, return false ***NEW***
    
                    bitl    x,#31           wcz     'make right-side comparable
            if_c    cmp     x,##$7F800001   wc      'NaN?
            if_z    neg     x                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_nc   skip    #%11111                 'if NaN, return false
    
                    cmps    w,x             wcz     'do comparison
            if_z    mov     y,#%1000                'equal?
            if_nz   mov     y,#%0100                'above?
            if_c    mov     y,#%0010                'below?
                    test    y,pa            wc      'test mask
    
            _ret_   muxc    x,_FFFFFFFF             'return boolean
    
  • remove the if_c on the 2nd cmp. Then it works.

    frel_           popa    w                       'pop left-side float
    
                    bitl    w,#31           wcz     'make left-side comparable
                    cmp     w,##$7F800001   wc      'NaN?
            if_z    neg     w                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_nc   skip    #%111111111             'if NaN, return false ***NEW***
    
                    bitl    x,#31           wcz     'make right-side comparable
                  cmp     x,##$7F800001   wc      'NaN?
            if_z    neg     x                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
            if_nc   skip    #%11111                 'if NaN, return false
    
                    cmps    w,x             wcz     'do comparison
            if_z    mov     y,#%1000                'equal?
            if_nz   mov     y,#%0100                'above?
            if_c    mov     y,#%0010                'below?
                    test    y,pa            wc      'test mask
    
            _ret_   muxc    x,_FFFFFFFF             'return boolean
    

    Tim

  • TonyB_TonyB_ Posts: 2,178
    edited 2023-09-25 10:35

    deleted

  • cgraceycgracey Posts: 14,151

    Remember those ##$7F80000x instructions need TWO skips to get over.

  • cgraceycgracey Posts: 14,151
    edited 2023-09-24 23:58

    Thanks for thinking this over. I am kind of leaning towards this:

    frel_           popa    w                       'pop left-side float
    
                    bitl    w,#31           wcz     'make left-side comparable
                    cmp     w,##$7F800001   wc      'NaN?
            if_nc   skip    #%1111                  'if NaN, return false
            if_z    neg     w                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
                    bitl    x,#31           wcz     'make right-side comparable
                    cmp     x,##$7F800001   wc      'NaN?
            if_nc   skip    #%111111                'if NaN, return false
            if_z    neg     x                       '+/- %0_xxxxxxxx_mmmmmmmmmmmmmmmmmmmmmmm
    
                    cmps    w,x             wcz     'do comparison
            if_z    mov     y,#%1000                'equal?
            if_nz   mov     y,#%0100                'above?
            if_c    mov     y,#%0010                'below?
                    test    y,pa            wc      'test mask
    
            _ret_   muxc    x,_FFFFFFFF             'return boolean
    

    There seems to be no way to shorten the ##value matter.

  • Thanks
    forgot the ##, should have had some nan test cases.
    I added 2 test cases, 1st parameter nan and 2nd parameter nan, and changed the code to match yours.
    All test cases pass, my reading of the code is comparision will return false if either parameter is NAN.

  • cgraceycgracey Posts: 14,151
    edited 2023-09-25 05:36

    @Timmoore said:
    Thanks
    forgot the ##, should have had some nan test cases.
    I added 2 test cases, 1st parameter nan and 2nd parameter nan, and changed the code to match yours.
    All test cases pass, my reading of the code is comparision will return false if either parameter is NAN.

    Thanks, Tim. I implemented those changes.

    Could you guys please test this new PNut_v40a.exe to see if it passes your FP equality operator tests?

  • Yes, its passing all my tests. I attached the debug output for my run so you can see the tests run.

  • cgraceycgracey Posts: 14,151

    @Timmoore said:
    Yes, its passing all my tests. I attached the debug output for my run so you can see the tests run.

    Ok. Super! Thanks, Tim. I will update everything now.

Sign In or Register to comment.