B4J Question Product of 24*60*60*180*1000 is negative and incorrect

xulihang

Active Member
Licensed User
Longtime User
B4X:
Dim result As Long
result=24*60*60*180*1000  
Log(result)
Log(Abs(result))
Dim direct As Long=1627869184
Log(direct)

Output:

B4X:
-1627869184
1.627869184E9
1627869184

I encountered a problem that a large product using a formula becomes negative while it is positive by directly assigning the value.

Actually, the result value is not correct, as well.
 

xulihang

Active Member
Licensed User
Longtime User
I have to define one of the numbers as long to get the correct result:

B4X:
Dim x As Long=1000
Dim result As Long
result=24*60*60*180*x

B4X:
15552000000
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Interestingly that seems to be a problem/feature with Java itself. B4A/J compiles the calculation as

Result = (long) (24*60*60*180*1000);

By default Java assume literal numbers are 32 bit integers. Java promotes values to that of the most precise type in the expression before doing a calculation and so is doing the calculation as 32 bit integers then casting the result to a long. Making one of the values a long doesn't apparently change the compiled code but does force Java to promote the other values to longs before calculating the result.

x = (long) (1000);
Result = (long) (24*60*60*180*x);
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
You can help the compiler (if you know the value will be large) by giving it a hint.
B4X:
result=24*60*60*180*1000.0d
Forces the 1000 to be considered as a double.
1000l (L) should work too but the ide sees it as an syntax error
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Nice question! Sometimes breaking my head why works and why not...

Erel answered that with "A Solution"

I am not extending the question ... but are the numbers "counted" as INTs because: for less memory ?
is it something that we can change and set them all by default double perhaps - am i asking too much ?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Large whole numbers, larger than the maximum value an Int can hold, are treated as Longs.
You don't want to treat whole numbers as double by default. It will have bad side effects.

but are the numbers "counted" as INTs because: for less memory ?
99.9% of the numbers that you use in your code are in the range of int. Treating them as long will have some performance and memory impact.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Upvote 0

Markus Winter

Member
Licensed User
You don't want to treat whole numbers as double by default. It will have bad side effects.

Which ones? As doubles can represent quite a large integer range precisely (much larger than 32bit Integers) I’m curious which side effects you are referring to?
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Will it always work as long as only ONE of them is a long and the rest are all ints?
No. If you want to avoid overflow issues, the first number must be a Long. This can be either by ensuring that the first number is a long variable or that the first number is a string literal that must be converted to a long (it is large enough not to fit into an Int).

For explanations on this, see

Making one of the values a long doesn't apparently change the compiled code but does force Java to promote the other values to longs before calculating the result.
If Java does this, B4X does not mimic that behavior. In order to avoid overflow, the first number used in the calculation should be of the desired output type (in this case Long). See the second link I posted above for proof by code.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Which ones? As doubles can represent quite a large integer range precisely (much larger than 32bit Integers) I’m curious which side effects you are referring to?
1. Changing the behavior of numeric literals, at this point, is not something that can happen as it will break backward compatibility ( [B4X] Backward Compatibility )
2. The performance of doubles (= 8 byte) calculations is worse than ints (= 4 bytes) calculations. This is not problematic in most cases, but it can be relevant in some compute-intensive tasks.
3. Comparing equality of doubles is a bit risky as small rounding errors can cause two numbers that are expected to be the same to be not equal.
4. It will break many JavaObject usages where the passed value is expected to be an Int. Int is the "standard type" for whole numbers.
 
Upvote 0

Markus Winter

Member
Licensed User
To be honest I am looking at B4 because I hoped it wouldn't have the same 32bit problems that Xojo has (and I'm not talking about the inherent phenomen of 32bit integer overflows, but how to deal with it)..

The problem is that 32bit integer overflows have caused planes to crash - so they really need to be taken seriously.

The following table lists the largest whole number that can be **accurately** represented by the different numeric types:

largest integer that can accurately be represented.png


[Early PCs had a mathematical co-processor that sped up floating point calculations - and programmers often used Doubles to avoid 32bit integer overflows on 32bit systems, and without any real speed penalties.]

Doubles and 64bit Integers have MUCH larger ranges of Integers that they can accurately represent than 32bit Integers.

Nowadays 2 Billion is not a big number anymore, so my (personal) opinion is that everything should use or at least allow 64bit Integers where "Integers" are expected - even on 32bit systems.

1) "Backwards Compatibility" in this context means keeping 32bit Integer overflows around, something that I don't find acceptable in Xojo or B4, especially as a 32bit system can deal with 64bit integers just fine. Is it some work? Yes. Can it be done? Yes. Should it be done? Definitely.

Funnily enough the suggested workaround for 32bit integer overflows is to turn it into a double … which kind of negates the argument that you can't do that because of backwards compatibility …

2) Performance? That's an argument that sounds sensible but that stopped being an argument about 15-20 years ago. Even a 10 year old computer is so fast that you won't notice whether you use 64bit integers or Doubles instead of 32bit integers (and as a Molecular Biologist I used to routinely analyse multi-gigabyte sized files of data on my 2010 Mac Pro).

3) the doubles accurately represent those integers - no problem with comparisons

4) That might be an argument. But I would argue that even on 32bit systems those objects should accept 64bit Integers. Sure, that's work - but with the current situation you might get different results on your 64bit system at home and the 32bit system at work … and that is just crazy.

Security and reliability should be the prime concern. If you can't trust the computer to do Maths correctly …?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
@Markus Winter note that B4X type system doesn't depend on the CPU architecture (with the exception of B4R in some cases). An Int is always a 32 bit integer.
ven a 10 year old computer is so fast that you won't notice whether you use 64bit integers or Doubles instead of 32bit integers (and as a Molecular Biologist I used to routinely analyse multi-gigabyte sized files of data on my 2010 Mac Pro).
A 2010 Mac Pro is likely to be faster than many mobile devices.

You can add .0 to all numbers if you want numeric literals to be treated as doubles. You can also add a sub that converts numbers to double:
B4X:
Public ToDouble(d As Double)
 Return d
End Sub
 
Upvote 0

MegatenFreak

Active Member
Licensed User
You can add .0 to all numbers if you want numeric literals to be treated as doubles.
So turning integers into doubles will also produce the correct result when it falls within the 'long' range, right?
Just to make things clearer for myself, which one of these methods is 'better', professionally? :
B4X:
'Method 1
dim n1 as long = 24
Log(n1*60*60*180*1000)
'Method 2
Log(24.0 * 60 * 60 * 180 * 1000)
 
Upvote 0

MegatenFreak

Active Member
Licensed User
Method 1 is better. Doubles cannot represent accurately all values.
Yeah, I had forgotten about an annoying experience I'd had with doubles, namely:
 
Upvote 0
Top