Bug? Error parsing string "-0" to float

emexes

Expert
Licensed User
This code (2 lines of diagnosis hacks + 1 original problem line):
B4X:
Dim TempString As String = lblReading.Text
Log("len = " & TempString.Length & ", str = [" & TempString & "] isnum = " & IsNumber(TempString))
       
Dim CurrentReading As Float = TempString    '''lblReading.Text
is producing this error when the string is "-0":
len = 2, str = [-0] isnum = true
Error occurred on line: 423 (Main)
Cannot parse: -0
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
PTOC -[B4I ObjectToNumber:] + 464
PTOC -[B4IRDebugUtils numberCast::] + 268
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
PTOC +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
PTOC -[B4IShell runMethod:] + 448
PTOC -[B4IShell raiseEventImpl:method:args::] + 1640
PTOC -[B4IShellBI raiseEvent:event:params:] + 1372
PTOC __24-[B4ITimer startTicking]_block_invoke + 332
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 412
libdispatch.dylib <redacted> + 1308
libdispatch.dylib <redacted> + 784
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
PTOC main + 124
libdyld.dylib <redacted> + 4
)

I tried some parsing test code at the start of the same program:
B4X:
Private Sub Application_Start (Nav As NavigationController)
   
    'SetDebugAutoFlushLogs(True) 'Uncomment if program crashes before all logs are printed.
   
    Dim TestString As String
    Dim TestFloat As Float
   
    TestString = "1.23"
    TestFloat = TestString
    Log(TestString & " = " & TestFloat)

    TestString = "-1.23"
    TestFloat = TestString
    Log(TestString & " = " & TestFloat)

    TestString = "0"
    TestFloat = TestString
    Log(TestString & " = " & TestFloat)

    TestString = "+0"
    TestFloat = TestString
    Log(TestString & " = " & TestFloat)
   
    TestString = "-0"
    TestFloat = TestString
    Log(TestString & " = " & TestFloat)
but it seems to work just fine on the offending "-0" (indeed: better than fine, since it looks like it implements the IEEE signed-zero nuance):
Application_Start
1.23 = 1.2300000190734863
-1.23 = -1.2300000190734863
0 = 0
+0 = 0
-0 = -0
Application_Active

Having mentioned the signed-zero nuance, perhaps I should tug on that loose thread a little harder.

But still, why would the same casting work in one case, fail in another? Especially when IsNumber says the string is ok.
 

emexes

Expert
Licensed User
I added some more diagnosis code, thinking that perhaps the string that looks like "-0" is actually some other Unicode characters that just look like "-" and "0" but are actually some other character that just looks similar:
B4X:
Dim TempString As String = lblReading.Text
Log("len = " & TempString.Length & ", str = [" & TempString & "] isnum = " & IsNumber(TempString))

Dim TempNegativeZero As String = "-0"
Log(TempString.CompareTo(TempNegativeZero))

Dim TempFloat As Float = TempNegativeZero
Log(TempNegativeZero & " = " & TempFloat)
Log((TempFloat * 100) & " " & (TempFloat + 100))

Dim CurrentReading As Float = TempString    '''lblReading.Text
but I still get the same error... even though the TempString and TempNegativeZero strings are identical (CompareTo = 0), and the assignment statements to local floats look identical, one parses ok and the other doesn't:
len = 2, str = [-0] isnum = true
0
-0 = -0
-0 100
Error occurred on line: 430 (Main)
Cannot parse: -0
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
PTOC -[B4I ObjectToNumber:] + 464
PTOC -[B4IRDebugUtils numberCast::] + 268
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
PTOC +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
PTOC -[B4IShell runMethod:] + 448
PTOC -[B4IShell raiseEventImpl:method:args::] + 1640
PTOC -[B4IShellBI raiseEvent:event:params:] + 1372
PTOC __24-[B4ITimer startTicking]_block_invoke + 332
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 412
libdispatch.dylib <redacted> + 1308
libdispatch.dylib <redacted> + 784
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
PTOC main + 124
libdyld.dylib <redacted> + 4
)
 

emexes

Expert
Licensed User
The generated code from B4I looks the same for both cases:
B4X:
@implementation ResumableSub_main_tmrBluetooth_Tick {
b4i_main* parent;
long long _t;
float _r;
float _g;
float _b;
NSString* _tempstring;
NSString* _tempnegativezero;
float _tempfloat;
float _currentreading;
int _bubbleleftmin;
int _bubbleleftmax;
float _x;
}
B4X:
B4IRDebugUtils.currentLine=983119;
 //BA.debugLineNum = 983119;BA.debugLine="Dim TempFloat As Float = TempNegativeZero";
_tempfloat = [self.bi ObjectToNumber:_tempnegativezero].floatValue;
...
B4IRDebugUtils.currentLine=983123;
 //BA.debugLineNum = 983123;BA.debugLine="Dim CurrentReading As Float = TempString    '''l";
_currentreading = [self.bi ObjectToNumber:_tempstring].floatValue;
so for the time being, I will just put it down to being one of life's little mysteries, and work around it.
 

emexes

Expert
Licensed User
Continued on my merry way, then - after several successful runs - got this:
Application_Start
1.23 = 1.23
-1.23 = -1.23
0 = 0
Error occurred on line: 98 (Main)
Cannot parse: +0
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
PTOC -[B4I ObjectToNumber:] + 464
PTOC -[ResumableSub_main_Application_Start resume::] + 2872
...
ie from this test case:
upload_2019-5-12_14-13-27.png

unchanged from the previous runs.
 

Cableguy

Expert
Licensed User
Longtime User
The IDE automatically cast string to numerical values...
I'm guessing the issue is the plus sign...
The IDE may see it as an arithmetic function rather than a positive number, since the lack of minus sign automatically define the positiveness of the number.
 

emexes

Expert
Licensed User
Re: the +0

The oddity was that it worked fine, then randomly stopped working.

I agree that many BASICs choke on leading-but-needless "+" signs. It's nice when it works, though, for things like polynomial coefficients, to emphasize that you haven't forgotten the sign.

I've done as much diagnosis as I can afford timewise right now, but just wanted to document it in case somebody else hits the same issue, so's they know they're not alone ;-)

The "-0" is the result of NumberFormat2(-0.123, 1, 0, 0, False).
 

emexes

Expert
Licensed User
I have narrowed the issue down slightly, and possibly added some mystery too: the error occurs when the "-0" string is from a TextField or Label, but not when it is from a string literal.

Two seemingly identical Strings, both "-0", one parses with no error, the other causes an error. Regardless of the order in which they are done, the "F = InputString" line fails with "Cannot parse: -0"

I am using B4I 5.30, with iOS 12.2 on an iPhone 5S.

Starting from a blank new project, I can reproduce the error reliably with:
B4X:
Private Sub Application_Start (Nav As NavigationController)
    'SetDebugAutoFlushLogs(True) 'Uncomment if program crashes before all logs are printed.
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    NavControl.ShowPage(Page1)
   
    Dim LiteralString As String
    Dim InputString As String
   
    Dim F As Float '''Double
       
    LiteralString = "-0"

    Dim TF As TextField
    TF.Initialize("TF")
    TF.Text = LiteralString ''' "-0"
    InputString = TF.Text
   
    Log(LiteralString.Length & " [" & LiteralString & "] " & IsNumber(LiteralString))
    Log(InputString.Length & " [" & InputString & "] " & IsNumber(InputString))
    Log(LiteralString.CompareTo(InputString))
       
    F = LiteralString
    Log("LiteralString " & F)
   
    F = InputString
    Log("InputString " & F)
   
End Sub
which logs the following error (after both IsNumbers return True, and Compare indicates strings are identical?):
Application_Start
2 [-0] true
2 [-0] true
0
LiteralString -0
Error occurred on line: 49 (Main)
Cannot parse: -0
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
B4i Example -[B4I ObjectToNumber:] + 464
B4i Example -[B4IRDebugUtils numberCast::] + 268
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
B4i Example +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
B4i Example -[B4IShell runMethod:] + 448
B4i Example -[B4IShell raiseEventImpl:method:args::] + 1640
B4i Example -[B4IShellBI raiseEvent:event:params:] + 1372
B4i Example __33-[B4I raiseUIEvent:event:params:]_block_invoke + 60
libdispatch.dylib <redacted> + 24
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 1068
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
B4i Example main + 124
libdyld.dylib <redacted> + 4
)
Application_Active
where line 49 is the "F = InputString" string-to-float conversion:
upload_2019-5-13_15-34-12.png

It has me stumped. Why would the memory location of the string make a difference to the parsing? Is there some protection mechanism kicking in, like the string-to-float parsing routine doesn't have access to the string data held inside TextField that is possibly still pointed to by the InputString string variable? I tried to force construction of a brand new string, by adding spaces and then Trimming it, but the error seems quite resilient.

My main worry is that IsNumber returns True on a string that generates a parsing error. I don't know how easy this is to fix, other than a simple filter for "-0" (and "-0.0" and "-0.000E+00" and...) vs what are the chances of somebody entering "-0" anyway ?
 

emexes

Expert
Licensed User
Hmm. The Trim function also "pollutes" the string, so it isn't just strings that have come from within views, eg:
B4X:
Private Sub Application_Start (Nav As NavigationController)
    'SetDebugAutoFlushLogs(True) 'Uncomment if program crashes before all logs are printed.
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    NavControl.ShowPage(Page1)
   
    Dim S As String
    Dim F As Float '''Double
       
    S = "-0"
    Log(S.Length & " [" & S & "] " & IsNumber(S))
   
    F = S
    Log(F)
   
    S = S.Trim    ''' "-0".Trim
    Log(S.Length & " [" & S & "] " & IsNumber(S))
   
    F = S    '''.Trim
    Log(F)
   
End Sub
results in:
Application_Start
2 [-0] true
-0
2 [-0] true
Error occurred on line: 42 (Main)
Cannot parse: -0
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
B4i Example -[B4I ObjectToNumber:] + 464
B4i Example -[B4IRDebugUtils numberCast::] + 268
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
B4i Example +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
B4i Example -[B4IShell runMethod:] + 448
B4i Example -[B4IShell raiseEventImpl:method:args::] + 1640
B4i Example -[B4IShellBI raiseEvent:event:params:] + 1372
B4i Example __33-[B4I raiseUIEvent:event:params:]_block_invoke + 60
libdispatch.dylib <redacted> + 24
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 1068
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
B4i Example main + 124
libdyld.dylib <redacted> + 4
)
Application_Active
where line 42 is the string-to-float conversion of the same variable S (albeit just trimmed, with no apparent effect):

upload_2019-5-13_16-16-33.png
 

emexes

Expert
Licensed User
I agree and I've changed IsNumber behavior to return False in this case.
Well, that'll fix it, I guess. I'm sad that I will no longer experience the thrill of seeing negative zero (sometimes) handled distinctly per IEEE, though ;-/

I trust non-zeroes like "-0.0123" will still be ok. Also, "-0.0E+01" generated an error, even though it has a non-zero digit in it.
 
Top