Rocket U2 | UniVerse & UniData

 View Only

 On Universe this command PRINT "108100636331677141" = "108100636331677134" prints 1.

Jump to Best Answer
Joe Goldthwaite's profile image
Joe Goldthwaite posted 03-22-2024 13:37

Both items are strings. They're not equal. It seems Universe is doing some kind of conversion on them that makes them equal.

If I convert the strings to integers it knows they're not equal. If I concatenate a letter on to either string it knows they're not equal.

 My client was using smaller numbers in a field but a new specification requires and 18 digit number. They don't want to to through all there programs that compare these numbers and modify them with a alpha character or int conversion.

Does anyone know what's going on and how to best fix it?

John Jenkins's profile image
John Jenkins Best Answer

Henry,

I think you have it on the nail there. I was musing about another BASIC compiler option (see below) but unfortunately it does  not take affect for comparison operations. I think it's definitely worth asking for an expansion as an enhancement as "long math"-related issues have arisen more and more over recent years, whether or not the string value was intended to be a number or if it was just happenstance.

  • $OPTIONS STRING.MATH Causes UniVerse BASIC to automatically use the SADD, SSUB, SDIV, and SMUL functions rather than +, -, /, and *. This option also applies to the INT, ABS, NEG, and MOD functions.

As a suggestion if only to make the inline code for comparisons more intuitive (someone may just think those INT() fiunctions are redundant in the future), create an user conversion exit (ICONV/OCONV)  function called (for example) $STRCMP that accepts two arguments and does the necessary to check they are string equal, regardless of content. This could be by the addition of a non-numeric character or a forced INT() as appropriate just to evaluate whether the two values are or are not string equal. Equally this could be a local function, though a global function is available without specific coding of $INCLUDE/$INSERT.

Regards

JJ

Joe Goldthwaite's profile image
Joe Goldthwaite

I think this is what's happening. When I compare the two strings above, Universe Basic is detecting that they're numeric strings and is trying to compare them as numbers. As part of the conversion to numbers, it must be rounding them to the nearest 16 digit integer. If you round the above strings to 16 digit integers they are equal.

This is clearly a bug however. If I have two strings I want to compare them as strings. Especially if they're long strings of characters.  I shouldn't have to do anything special to compare two long strings just because they happen to all be made of of characters 0-9.

In this case, the strings are coming from both a file and a scangun.  I'm not performing any math operations against them. They shouldn't be attempting any number conversion before doing the compare.

Are there any $OPTION or account flavor settings that will fix this???

John Jenkins's profile image
John Jenkins

Joe,

Please look at SCMP() which shoudl do what you want I think. Otherwise opening a Support ticket. 

Regards

JJ

Joe Goldthwaite's profile image
Joe Goldthwaite

Hi John,

It looks like it's a bug then. This code:

A = "108100636331677141"
B = "108100636331677134"
PRINT SCMP(A,B)

Prints "1" so it still thinks those two strings are equal. 

Strangely, "PRINT A+0 = B+0" prints "0" so it knows they're not equal. 

It seems like I knew the answer at one point. The issue is very familiar but I can't find anything in my emails, notes or online posts about it.

I don't have much faith in a Rocket support ticket. We might have to force the compare by prefixing all the the numbers with a character. That would make them all 19 characters but putting an alpha number in the first position avoids this bug. It will require going through all our code that references the number and adjusting it. Not something anyone wants to do right now.

Henry Unger's profile image
PARTNER Henry Unger

A = "108100636331677141"
B = "108100636331677134"

crt 'A = B = ' : (A = B)

A = INT(A)
B = INT(B)

crt 'A = B = ' : (A = B)

Result:

A = B = 1
A = B = 0

When UniVerse does a comparison of two strings it tries to convert them to floating point numbers before comparing them, which is why it thinks they are the same. If you first coerce them to integers then they will not be the same as of when UniVerse started supporting 64 bit integers some time ago.

Henry

Joe Goldthwaite's profile image
Joe Goldthwaite

Hi Henry,

That makes sense.  Thinking about it, I've been thinking that forcing a numeric compare against two strings is a bug. I was thinking that if I wanted a numeric compare I would a zero to the string to force a conversion. Maybe that mindset was coming from all the work I've done in other languages.

Thinking about it further I can understand Universe's default. Everything coming from a dynamic array is a string. If you didn't check for a number before comparing values it would screw things up since, for example, 2 would be considered > 10.

I think the problem here is that they're converting to floating point first. I'd say don't do that unless you've got a decimal in the string. That would leave integer strings as integers and keep this specific scenario from happening. Floats are weird anyway.  It's best to avoid them unless you need high precision. In most business applications, you don't.

I wonder if the other MVDB flavors have the same issue?

Anyway, thanks for the help John and Henry. I appreciate it.

Kurt Neumann's profile image
Kurt Neumann

Hi Joe

Check out the UniVerse configurable parameter EXACTNUMERIC.

EXACTNUMERIC - Specifies the number of digits of precision before rounding occurs. The maximum is 57 digits and the minimum (default) is 15 digits.

Increasing this should address your problem.

Joe Goldthwaite's profile image
Joe Goldthwaite

Hi Kurt,

That sounds like what we're looking for but it looks like it can affect a lot of other things. I don't think we can safely use it without a lot of testing of the entire system. That's not practical right now.

This pointed me to the WIDE0 parameter which looks like it directly affects how the double precision numbers are compared. This looks like an even closer match to fix our specific issue. It suffers from the same issue though. It potentially affects other areas that we have no way to effectively test.

We've decided that the safest approach in our case is to append "A" to the numeric strings whenever we use the equal operator. Since the values are all fixed at 18 digits, a string compare will always work even if we're checking GE or LE. It completely avoids Universe's penchant of doing a number conversion first.  Using the INT function would also work but I worry that on a different system it might also have trouble with an 18 digit number so out of precaution, I'm avoiding that also.

Thanks again to everyone who has posted. I appreciate the time you've taken.