All control instructions test either ints or references. If you want to do a branch based on a comparison between two floats, longs, or doubles, you have to use a separate instruction to turn the non-int comparison into an int comparison. The instructions to do this are summarized in Table 5.2. These instructions leave 1, 0, or 1 on the stack if the first operand is greater than, equal to, or less than the second. This value is easily compared with zero as an int, using the ifeq, ifne, iflt, ifgt, ifle, or ifge instructions. For example, comparing double values:
getstatic java/lang/Math/PI D ; Get a good approximation of pi ldc2_w 3.1416D ; Get a worse approximation of pi dcmpg ; Compare the two numbers ; This leaves 1 on the stack, ; since pi < 3.1416 iflt approxTooHigh ; Goes to approxTooHigh, since ; 1 < 0
Or for long values:
; Push the current time in milliseconds, a long value invokestatic java/lang/System/currentTimeMillis()J aload_0 ; Push a Document getfield Document/lastUpdatedTime J ; Get the last time this ; document was updated lsub ; Figure out the difference ldc 60000 ; Was it more than 60 seconds ago? lcmp ; Leaves 1 if more than 60 seconds ; 0 if exactly 60 seconds, and ; 1 if less than 60 seconds ifle makeBackup ; Make a backup if it was updated ; <= 60 seconds ago
For the float and double comparisons, there are two almost identical operations for each: fcmpg/fcmpl and dcmpg/dcmpl. The difference is in the treatment of values that are NaN (not a number). Since NaN isn't really a number, it can't be compared to the other values. You choose the g variant or the l variant based on how you want your program to react if it encounters invalid numbers. If you want to see if a > b and you use dcmpg, then the test will succeed if either is NaN. If you use dcmpl, it will to fail.