Diese Seite mit anderen teilen ...

Informationen zum Thema:
Forum:
WinDev Forum
Beiträge im Thema:
22
Erster Beitrag:
vor 4 Jahren, 9 Monaten
Letzter Beitrag:
vor 4 Jahren, 9 Monaten
Beteiligte Autoren:
GuenterP, Steven Sitas, Alexandre Leclerc, Arnaud Benhamdine, Jose Antonio Garrido, Fabrice Harari, Viggo Poulsen, stefan.kern

The problem with math calculations in WinDEV 17

Startbeitrag von Steven Sitas am 08.09.2013 15:34

Hi,
I already posted this week a problem I had with Reals in windev code, but now I have found a realy DANGEROUS BUG in WD17.

Here is a small example that shows the problem:
nMyNum is int
rMyReal is real

nMyNum=100 * 0.29
rMyReal=100 * 0.29

Info(nMyNum,rMyReal)
------------------------------

After execution nMyNum=28 and rMyReal=29 !!!!!
The WD JIT compiler is doing some "dumb" things.

And it ONLY does it with 0.29 ..................

So whenever you are doing ANY kind of calculations with decimals (even 1 or 2 decimals) NEVER assign them to an integer, even if you are sure that the calculation SHOULD be an integer - like above.
Always assign them to a Real or Numeric or Currency.

This is a WD compiler BUG not a problem with Reals.

Steven Sitas

Antworten:

Hi Steven

Same result in WD18

von Viggo Poulsen - am 08.09.2013 17:15
Same in WD15

but:

nMyNum is int
rMyReal is real
xMyNUM is numeric


nMyNum=100 * (0.28 +0.01)
rMyReal=100 * (0.28 +0.01)
xMyNUM=100 * (0.28 +0.01)

Info(nMyNum,rMyReal,xMyNUM)

is correct!

Always 29

von stefan.kern - am 08.09.2013 19:07
Hi Steven,

this is the way WinDev worked since version 5.5, at least as far back as I know.
You're forcing WinDev to do an implicit type conversion.
This is no good in any programming language, because you'd have to learn the rules of how a specific programming language really works.

Here, since reals are never exactly the same like input, in reality (= RAM, disk, memory) your definition of 0.29 may be 0.2899999 and forcing to convert that float value of 28.999999 to an integer inevitably will result in 28. Simply, everything after the comma will be cut away!! This is how a conversion to integer will always work in WLanguage!!

How to make it work:

MyReal1 is 4-byte real = 0.29
MyReal2 is 4-byte real = 100
MyInteger1 is 4-byte int
MyInteger2 is 4-byte int

MyInteger1 = MyReal1 * MyReal2
MyInteger2 = Round(MyReal1 * MyReal2,0)

MyInteger1 will be - correctly!!! - 28
MyInteger2 will be 29

von GuenterP - am 09.09.2013 06:56
Hi Guenter,
I know where the problem is and how to make the code work !!!!
Every compiler I know, knows what to do with this expression 100*0.29.
It would treat it as a Real (or currency or Numeric) and would ofcourse return 29.
After doing the above calculation, it would then return/assign the value 29 to any kind of variable (even a to a string)

Please note that this IS NOT a problem with Reals and its representation.
The Windev compiler FAILS to see that this is a REAL expression and does some really dumb things !!!!

When it sees integer = 100 * 0.29, IT WRONGLY assumes that EVERYTHING is an integer (in the expression) and ofcourse it gets it wrong.
If you change the above code to 100*(0.28 + 0.01) it works just fine !!!!
The expression 0.28 + 0.01 helps the compiler to see that it needs to really do Real arithmetic and for some reason/bug it cant catch the 0.29 (which is a Real)

The funny thing is that the problem is only with .29 (not .39 or .49 etc).

This is definetly a COMPILER/INTERPRETER Bug and has NOTHING to do with problems with REALs.

Everyother language I work with has no problem with the above code ....

Steven Sitas

von Steven Sitas - am 09.09.2013 10:36
Hi Steven,

obviously, you still don't understand what's really happening ...

It is NOT AT ALL the multiplication part, it's the WinDev-inherent way of how a real is converted to an integer.
PC Soft is consistent with this way of conversion, at least since WinDev 5.5 !

You just have to know that in WLanguage conversions from real to integer will cut off everything after the comma from the real.
With other compilers for other programming languages this may be different.

And here's the proof that your assumption of a compiler bug is wrong:
If your theory of a hidden integer multiplication would be correct then

180 = 12.7 * 15.7

right? Following your theory, that a hidden integer operation takes place, the .7 of both operands should be simply cut off!
Therefore, still following your theory, the result should be 180.

It is not! It will show 199 as a result!!!

von GuenterP - am 09.09.2013 14:20
Hi Guenter,
It could be my English, but I think I was quite clear in my post.
I never said that there is a "hidden integer multiplication" in the expression, at least not the way you are interpreting it !!!!

Here is what I stated - from my post:
"The Windev compiler FAILS to see that this is a REAL expression and does some really dumb things !!!!"

What it does, I realy have NO IDEA.
Just for the fun of it, I will "dissasemble" 100*0.29 and get back to you ....

But actually your paradigm 12.7 * 15.7, shows that WinDEV can handle Real expressions and return the integer part to an integer.

I also suspect that you won't be able to find ANY OTHER combination of this kind:
100*0.xx or 10^2*0.xx or 10^(4-2)*0.xx
that will return this error.
My investigating shows that 0.xx must be equal to 0.29


Steven Sitas

von Steven Sitas - am 09.09.2013 15:15
Hi Steven, obviously, it's impossible to explain the facts to you!

Here is what I stated - from my post:
"The Windev compiler FAILS to see that this is a REAL expression and does some really dumb things !!!!"


No, it does no dumb things! If you took the time to read my post, you'd find the clear answer.
It does not fail to see anything, YOU set the real expression equal to an integer variable and expect that some magic would happen.
The WinDev rule is that in such a case all decimal places of the real will be cut off.
Fact is, that 0,29 will be represented in memory by 0,289999992 - you see?
(test it yourself by setting an Edit control with enough decimal places like 99999.999999999 )
Multiply that by 100 = 28,9999992 in memory
Cut off the decimal places = 28

There's no compiler bug, nothing .. sorry.

von GuenterP - am 09.09.2013 15:59
Hi Guenter,
You haven't read my posts carefully :)
Test your theory with 0.27 (or 0.39 or 0.19) ...

IT ONLY HAPPENS with 0.29 !!!!!

To end the story, BUG is confirmed and will probably be fixed in version 19 !!!!!

Steven Sitas

von Steven Sitas - am 09.09.2013 16:11
Hi Steven,

no, it's not a bug. They just confirm the receit of anything which ist not understandable during the first five minutes of reading.

Let me show you what's the result with 0.39
[attachment 644 Ashampoo_Snap_2013.09.09_19h16m28s_001_.png]

You simply get a similar result. The key to your understanding is that you don't use sufficient places behind the comma!
I'm sure, I can show you anomalies with most numbers, because 'floating point variables' tend always to be a little less than the value!

von GuenterP - am 09.09.2013 17:21
Hi,

This is a very interesting thread. In fact this is hapening with:
.29
.57
.58


FOR i = 1 TO 99
ExecuteCode("n is int = 100 * 0."+NumToString(i,"02d")+"; Trace(n, n"+i+" ? ""


von Alexandre Leclerc - am 09.09.2013 17:27
Hi Guenter,

I'm using real since forever with no problems (but never in the way Steven made it in fact). But I always used the assumption that real 4 has 6 significant digits, etc. So this is whay I'm surprised of the result too. But I totally agree and understand your point.

Maybe this is just the way WD does typecasting. Even if you change my example to do "r is real = 100*0.29; n is int = r; ..." well, you will have the same bad result. You must round yourself to bypass it.

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 09.09.2013 17:35
Hi Guenter,
of course you are right 100% of what you are saying about Reals and the way they are represented. And the problems that can show up.

But as I have stated in this post - this has to DO with the way the WD Interpreter makes a decision ON how to calculate expressions.

So when it decides to treat this expression (100 * 0.29) as a FLOATING calculation, it makes a TERRIBLE mistake.
Todays compilers are VERY SMART and FIRST CLASS compilers would NEVER treat the above as floating point math.
Maybe because WD is not a true compiler and uses JIT compilation?
I wonder how JAVA works under similar conditions?

Ofcourse with your paradigm - with the edit fields - I don't expect the compiler to do anything different. It actually gets Reals and ofcourse it does the rounding.

But simple expressions like 100*0.29 - this it must handle in common logic !!!!!

von Steven Sitas - am 09.09.2013 17:46
Hi Alexandre,

I believe WLanguage is absolutely correct here. Imho, arbitrary changes (= rounding?) of values without notification to the programmer would be dangerous in some situations. However, as you say, one has to expect anomalies when writing things like MyInteger = MyReal4 . There are many situations alike, no one in his right mind would set MyString1 = MyReal8 etc. Of course, WLanguage offers an auto-conversion here too, but calling any unexpected result a bad 'bug' .. no, this is too much.

Maybe, WLanguage should even evolve to become more strict with such situations and issue a compiler error whenever the result of a calculation is of different type to the result variable's type. 'Error: Incompatible Types in Result and Operation"? Of course, it would be necessary to supply adequate conversion functions like ConvertRealToInt(value, rounding )

- a programmer can do the rounding himself, in WLanguage there is the Round(..) function.
- WLanguage supplies the functions and properties IntegerPart and DecimalPart to handle these situations in a more detailed way.
- one could write their own rounding algorithm if the function Round is not good enough.

von GuenterP - am 10.09.2013 07:14
Hi Guenter,

I was thinking of that behavior from the example I provided. And I did not remark it at first, but it looks like there is a pattern. So I expanded my test to check if there was a binary pattern or something in the like and it looks so. Run the following in a button:


sIntToBinS is string = [
PROCEDURE IntToBinS(n is int)
s is string
FOR i= 16 TO 1 STEP -1
s += n[ i ]
END
RESULT s[[TO 8]] +" "+ s[[9 TO]]
]

sWriteError is string = [
PROCEDURE WriteError(nSource is int, nResult is int)
RESULT " " + nResult + " (Source: " + IntToBinS(nSource) + " -> Result: " + IntToBinS(nResult) + ")"
]

Compile("IntToBinS",sIntToBinS)
Compile("WriteError",sWriteError)

FOR nHundred = 0 TO 16
FOR i = 0 TO 99
ExécuteCode("n is int = 100 * "+nHundred+"."+NumToString(i,"02d")+"; Trace(n, n"+((nHundred*100)+i)+" ? WriteError("+((nHundred*100)+i)+",n) ELSE """")")
END
END


11101, 111001, 1110001 (and some derivatives, there is a sub-pattern after...) These are all multiples of 29 linked to a binary sequence:

1*29, then

2*29 with (2*29)-1, then

4*29 with (4*29)-1, -2, -3, then

8*29 with more complex pattern that kicks in: (8*29)-2, -4, -6 plus mirror image of that with -25 and +25, except that for the original 8*29 there is no +25 (i.e. 207, 232 but not 257!)

16*29 with same weird pattern. (16*29)-4, -8, -12 plus double mirror image with +/-25 and +/-50 with the exception of (16*29)+50, again!

32*29, and (32*29)-8, -16, -24, plus quad mirror image with +/- 25, 50, 75, 100 with the same exception that (32*29)+100 is not present.

Etc.

So to me this looks like a clear pattern. But let's see what will come out from the Free Technical Support. (I sent them this interesting test.) Whatever the outcome, this was an interesting study.

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 10.09.2013 14:08
Hi Alexandre

they will answer you that:

- this is the normal behavior or reals
- always have been
- always will be
- reals have been "engineered" this way at a time when each byte counted, and therefore are "skipping" some values in order to save space.
- this is the same for ALL languages, and you'll find plenty of references of this on the web

This is why more MODERN types of numeric variables have been added (first currency, then numeric) in order for everybody to be able to STOP USING REALS... Which everybody should do

Best regards

von Fabrice Harari - am 10.09.2013 15:23
Hi Fabrice,

generally, you're absolutely right! However, reals do have their merits

1 - Nowadays, every processor chip has a co-processor unit for floating point arithmetic (note: but not for BCD arithmetic!). When keeping to IEEE standards the compiler will hand over all floating point operations to this co-processor and do the operation in no time! Seemingly, even RISC processors like ARM sport a floating point coprocessor unit. http://www.anandtech.com/show/6971/exploring-the-floating-point-performance-of-modern-arm-processors

While floating point operations are executed with high speed by dedicated hardware, BCD calculations are done using the compiler's library for BCD ops. Of course, BCD ops are heavily using the processor's ALU for integer arithmetic, but BCD calculations still rely on software, not hardware. I'm too busy to set up a test configuration in order to compare WLanguage's floating point and BCD arithmetic, but I'm 100% sure that floating point performance is much, much better than that of BCD arithmetic.

Bottom line: if you're doing heavy calculations then it's strongly recommended to use floats/reals instead of BCD/numerics! This may apply to simulations, to optimization runs where genetic algorithms with a high number of contraints (conditions) are at work, it may save you half a night for each run.

2 - Floating point numbers can cover a huge range of figures! An 8-byte real can represent a value from 1.7*10-308 to 1.7*10+308 with 15 significant digits. For commercial software like ledgers, CRM systems etc. this info will be of no value. For some scientific calculations this may be of big importance.

von GuenterP - am 10.09.2013 16:47
Hi Fabrice,

So far, so good. You are probably right and I understand what you say. The downside is that WinDev typecasting is not coherent when dealing with integers. It does a good job for string, currency, numeric, etc. But not for integer or integer related.


r is real = 100 * 0.29
s is string = r
mo is currency = r
nu is numeric = r
n is int = r // nop
d is Duration // nop
d..InSeconds = r
Trace(r,s,mo,nu,n,d) // 29 29 29 29 28 0000028999


One can ask himself how come it behaves as expected casting a float to a string, currency or numeric, but not when it comes to integer. If this is "known behavior" only for integers, fine.

But it seams that other modern languages are casting correctly. This simple test with Go language produces good behavior (you can copy-paste the code in the yellow box and click run at: http://golang.org/)


package main
import "fmt"
func main() {
var f float32
var n int
for i := 0; i


von Alexandre Leclerc - am 10.09.2013 17:44
Hi Alexandre,

IF verybody sticks to the IEEE 754 standard http://en.wikipedia.org/wiki/IEEE_floating_point which defines the floating point representation THEN I can't see differences based on the floating point variables themselves. So, it would be interesting to inspect the float representation of such programs. If they're the same and results are still different then I'd assume that something else within these programming languages is different, but not the floats.

von GuenterP - am 10.09.2013 20:27
Hi.

Well, i also think is a problem of WINDEV.
In this so high level lenguage, if I write the expression:

MyInt = 100 * 0.29

It should store the correct value, since i'm not forcing it to use reals or to discard the decimal part.
I'm sure that in any other modern development tool that code either will work correctly or will generate a warning o error when compiling.
And one more strange behaviour. I you decide to generate a windows executable, or a java archive, the result will be different!!

n is int = 100*0.29 // result is 28 if you run .exe, 29 if you run .jar

Regards,
José Antonio.

von Jose Antonio Garrido - am 10.09.2013 22:39
Hi Jose,
thanks for the example with the java archive.
As I said from the beginning, the problem is NOT with the IEEE 754 standard, as stated by Guenter.

The IEEE 754 standard is quite clear : if you do floating point on this expression 10*0.29 you will get 28.
PC Soft is OK with the IEEE 754 standard and I can't complaint about that !!!!

What I am talking about and Guenter doesn't seem to get it, is that the WinDEV compiler is using floating point and the IEEE 754 standard to calculate 10*0.29 !!!!!!

This is THE PROBLEM and NOT the IEEE 754 Standard.

Every other major language I have tested, NEVER uses the IEEE 754/floating to calculate 10*0.29, even if it is assigned to an integer ....

Since this behaviour in WinDEV is coming from the earlier versions, maybe PC Soft is afraid it would break some older code if it changed the compiler? They could ofcourse use some kind of compiler setting to bypass this problem.

But it is a VERY dangerous situation - that's why I did the original post.
And it has nothing to do with the quality of a programmer - it can happen to any of us.

Please NOTE that PC Softs programmers had this type of "problematic code" in there examples up to (including) version 15 !!!!!!

von Steven Sitas - am 11.09.2013 18:50
Hi Steven,

Your post is very clear from the beginning.

The problem is NOT related to the real representation in memory by Windev, which is compliant with the floating calculation, BUT to the choice of the compiler to use floating calculation to calculate "10*0.29".

It's definitively a bad choice for the compiler, ESPECIALLY when the programmer intend to assign the result to an integer... (but not only).

Regard, Arnaud.

von Arnaud Benhamdine - am 13.09.2013 10:01
Zur Information:
MySnip.de hat keinen Einfluss auf die Inhalte der Beiträge. Bitte kontaktieren Sie den Administrator des Forums bei Problemen oder Löschforderungen über die Kontaktseite.
Falls die Kontaktaufnahme mit dem Administrator des Forums fehlschlägt, kontaktieren Sie uns bitte über die in unserem Impressum angegebenen Daten.