Java What does c = t < 0 in C mean?

Tags:
1. Jul 6, 2015

Paul Uszak

This is a very basic question, but one that's vexed me for a while. Are these two fragments equal:-

In C, with c and t as integers
c = t < 0

and in Java, also with integers
if (t < 0) {
c = -1;
} else {
c = 0;
}

Reason I ask is that my Java interpretation works with any combination of t & c, and I can't tell which is the correct translation...

2. Jul 6, 2015

phinds

I don't do JAVA but my understanding is that it is a strongly typed language and as such it should have inherent "true" and "false" variables and your c variable in JAVA should be typed as boolean, so I'd say your JAVA statements should use true and false, not -1 and 0. Does JAVA do auto-conversion from integer to Boolean?

3. Jul 6, 2015

D H

Staff Emeritus
No. Fortran has this right. C/C++, and languages based on it such as Java, have it wrong (in my opinion).

In C, c = t < 0 sets c to zero or one. The problem with that is that zero and one differ by one bit. This is not a good idea in an environment that is prone to random bit flips.

OTOH, Fortran seeks to make boolean expressions such as t < 0 evaluate to two values that are diametrically opposed, bitwise. Your Java code emulates how Fortran works. It uses -1(all bits set on a two's complement machine) rather than 1 (only the least significant bit set).

4. Jul 6, 2015

wle

In C, this is read as c = (t < 0) and does the same thing as
Code (C):
if (t < 0) {
c = 1;
} else {
c = 0;
}
Java has a separate boolean type and doesn't support casting booleans to integers or vice versa, so in Java c = t < 0 is equivalent to
Code (Java):
if (t < 0) {
c = true;
} else {
c = false;
}
which the compiler will choke on if c is of type int.

How to "translate" the C code into Java depends on why you're doing this and what you want to accomplish. If there's a specific reason you want to assign integers like 1 or 0 to c, then assign those integers. If you just want to save the result of a test, then make c a boolean:
Code (Java):
boolean c;

c = t < 0;

[Edit: Since C99, C also defines a boolean type (_Bool), but it's effectively an integer that can only be assigned values 0 and 1 and isn't integrated into the language the way boolean is in Java (e.g. the C language standard says that the value of the expression t < 0 is of type int rather than _Bool).]

Last edited: Jul 7, 2015
5. Jul 7, 2015

Paul Uszak

This is the entire code (sic). Should have posted it earlier. Now I'm starting to doubt that it's C at all. I assumed that it was C. It's from:-

Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications
David Jones, UCL Bioinformatics Group
(Last revised May 7th 2010)

Code ( (Unknown Language)):

/* Implementation of a 32-bit KISS generator which uses no multiply instructions */
static unsigned int x=123456789,y=234567891,z=345678912,w=456789123,c=0;
unsigned int JKISS32()
{
int t;
y ^= (y<<5); y ^= (y>>7); y ^= (y<<22);
t = z+w+c; z = w; c = t < 0; w = t&2147483647;
x += 1411392427;
return x + y + w;
}

My problem lurks within the line beginning t = z... I think that c must be a number and not a boolean as it's used in an addition in this line. The code runs with my interpretation, but also with others and all produce reasonable output. This means I can't fix it. So help please!

6. Jul 7, 2015

Staff Emeritus
By precedence, one can rewrite it as c = (t > 0), and the equals sign expresses assignment. So that means c is?

Also, in C, what is 1 + false?

7. Jul 7, 2015

wle

That's C code, but (among other things) it's meant to be easy to translate to languages that don't have an unsigned integer type (like Java). It's written not to use multiplication because multiplication works differently for signed and unsigned integers.

To get the equivalent result in Java:
• Change y ^= (y>>7); to y ^= (y>>>7); (i.e., use Java's "unsigned right shift" operator).
• Change c = t < 0; to c = (t < 0) ? 1 : 0;.

It's probably a good idea to try out both the C and Java versions and check that they produce the same sequence.

Last edited: Jul 7, 2015
8. Jul 7, 2015

Paul Uszak

Thanks. And should all the variables be longs or shorts, because again it works well with both..? I suspect longs if they're to operate unsigned. But then it's meant to be 32 bit and not 64 bit. (I HATE SIGNED JAVA ESPECIALLY BYTES)

9. Jul 7, 2015

wle

int, since the algorithm is meant for 32 bit integers. Some of the numbers will be interpreted as negative in Java, e.g. if you print them to the console or multiply them by other numbers, but the bit sequences in memory should be the same.

If you really need the result to be a positive integer, you can always add 2L << 31 (i.e., $2^{32}$) if the result is negative and save the result as a long at the end.

10. Jul 8, 2015

newjerseyrunner

Okay, I see some dangerous talk about types here.

Remember
char <= short <= int <= long <= long long

You have absolutely no guarantee that an int is 32 bits, you don't even have a guarantee that these are different. If you want to assure yourself certain sizes:

Code (Text):
#include <cstdint>

int8_t my8bit = 111;  //Always 8 bit
int16_t my16bit = 1111; //Always 16 bit
int32_t my32bit = 11111;  //Always 32 bit

11. Jul 8, 2015

D H

Staff Emeritus
It's definitely C code. In C, the comparison operators (<, >=, >, <=, ==, !=) evaluate to zero or one, not false or true.

Why are you using this? In one thread, you want bits from pi as a source of pseudo random numbers. Now you are trying to use some variant of KISS. Why? I've asked you before, you haven't answered.

The answer to "Is X a good source of pseudo random numbers" depends very much on the application. If your goal is to add a bit of apparent randomness to a video game, even rand() is probably OK. You need to toss rand() if your goal is to perform some Monte Carlo analyses that depend on a PRNG with good frequency behaviors. Mersenne Twister works great (and is very fast) for this kind of application. You need to toss Mersenne Twister if your goal is cryptographically secure encryption. You also need to toss bits from pi, KISS, and a boatload of other pseudo random generators. Generating a sequence of cryptographically secure random numbers is a hard problem. There are cryptographically secure PRNGs, but in general they aren't very good for video games or Monte Carlo (too slow).

12. Jul 8, 2015

wle

This is all fixed in Java: ints are 32 bit signed two's complement integers that wrap around on overflow. It's not platform-dependent like in C.

13. Jul 8, 2015

newjerseyrunner

Endianness is consistent too, where in lower level languages, you have no guarentee

14. Jul 8, 2015

Staff: Mentor

this compiles as C code(gcc 3.4.2) : gcc -C -Wall kiss.c
Code (Text):

// unrolling this code so you can see it better.
// file:kiss.c
/* Implementation of a 32-bit KISS generator which uses no multiply instructions */
static unsigned int x=123456789,
y=234567891,
z=345678912,
w=456789123,
c=0;  // c is zero here
unsigned int JKISS32()
{
int t;
y ^= (y<<5);
y ^= (y>>7);
y ^= (y<<22);
t = z+w+c;    // c is still zero here
z = w;
c = t < 0;    // c becomes 0 or 1 here
w = t&2147483647; // no c here
x += 1411392427;  // no c here
return x + y + w;
}

MY question is:
Where does c have ANY effect on ANY calculation above as presented?
Code (Text):
c = t < 0;
is dead code unless the c variable is used somewhere else.
For example JKISS32() is called from a loop somewhere else we cannot see -- which is my guess.
c varies from 0 to 1 depending on whether the t variable is negative or not negative assuming this code is called iteratively.

Last edited: Jul 8, 2015
15. Jul 8, 2015

wle

Well that's the point. c can be set to 1, which can affect subsequent calls of JKISS32().

(In case you haven't read the whole thread, JKISS32() is meant to generate a pseudo-random sequence of numbers, so presumably it's going to be called more than once. Otherwise you may as well just do this.)

16. Jul 8, 2015

D H

Staff Emeritus
The current value of c impacts the output from JKISS32 via the calculation t = z+w+c. The updated value of c will affect the output from the next call to JKISS32(). This is a "Keep It Simple and Stupid" (hence the name) pseudo random number generator. Presumably it will be called many, many times during the course of an application's execution.

17. Jul 8, 2015

Paul Uszak

Thanks all so far for your patiences.

I've run the following with amendments suggested in this thread...

Code (Text):

public static void main(String[] args) {
int x = 123456789, y = 234567891, z = 345678912, w = 456789123, c = 0, t;

for (int i = 0; i < 10; i++) {
y ^= (y << 5);
y ^= (y >>> 7);                    // One > added from PF
y ^= (y << 22);
t = z + w + c;
z = w;
c = (t < 0) ? 1 : 0;               // 1 or 0 amendment from PF
w = t & 2147483647;
x += 1411392427;
int next = x + y + w;
System.out.println(next);
}
}

which produces this output...

-1714832263
-368852369
653136079
-1337015847
-162232845
-312426689
-302024013
-538639081
-639205643
-541828828
-204917723
1413940082
850185154
-87394344
-1847399219
-563371111
1218772128
-1940900712
-1922709363
-1395979365

This looks reasonable, if a little negative. Is there are chivalrous knight out there that might compile and execute the original C code for comparison? I don't have the resources to do so myself and I get a D in C.

18. Jul 8, 2015

Staff: Mentor

With regard to c - please note what I said later on. If the function were iterated it would have an effect, but did nothing to change the return value as presented.
The question seemed to be posed from the point of view of: ignoring iteration for the benefit of learning.

19. Jul 8, 2015

wle

Sure:
Code (Text):
$clang jkiss.c$ ./a.out
-1714832263
-368852369
653136079
-1337015847
-162232845
-312426689
-302024013
-538639081
-639205643
-541828828
-204917723
1413940082
850185154
-87394344
-1847399219
-563371111
1218772128
-1940900712
-1922709363
-1395979365
Exact code run:
Code (C):
#include <stdio.h>

static unsigned int x = 123456789, y = 234567891,
z = 345678912, w = 456789123, c = 0;

unsigned int jkiss32(void)
{
int t;
y ^= y << 5;
y ^= y >> 7;
y ^= y << 22;
t = z + w + c;
z = w;
c = t < 0;
w = t & 2147483647;
x += 1411392427;
return x + y + w;
}

int main(void)
{
for (int i = 0; i < 20; ++i)
printf("%11d\n", (int)jkiss32());
return 0;
}
I printed the result as an int to compare the negative values.

Last edited: Jul 8, 2015
20. Jul 8, 2015

wle

You should also really consider structuring the Java code instead of dumping the JKISS algorithm in main(). Java annoyingly insists that you pretend your entire program is object-oriented even when it's not, and I haven't used it in about ten years, so I'm not sure what the best way to handle this is. One approach might be to make the random number generator a static function in its own class (my recollection is that the math library is or was implemented this way), pretending it's a namespace:
Code (Java):
import java.io.*;

class JKISS {
static int x = 123456789, y = 234567891,
z = 345678912, w = 456789123, c = 0;

static int jkiss32() {
int t;
y ^= y << 5;
y ^= y >>> 7;
y ^= y << 22;
t = z + w + c;
z = w;
c = (t < 0) ? 1 : 0;
w = t & 2147483647;
x += 1411392427;
return x + y + w;
}
}

class RngTest {
public static void main(String[] s) {
for (int i = 0; i < 20; ++i)
System.out.format("%11d\n", JKISS.jkiss32());
}
}
which you can run with java RngTest (after compiling this) from the console.

21. Jul 8, 2015

Paul Uszak

wle, you're my shining knight

Brilliant! Exact match. Even brillianter is that I just ran the output through ENT (Fourmilab) and got...

Code (Text):

C:\scratch>ent jkiss32-1gb.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 1000000000 byte file by 0 percent.

Chi square distribution for 1000000000 samples is 266.30, and randomly
would exceed this value 30.07 percent of the times.

Arithmetic mean value of data bytes is 127.5008 (127.5 = random).
Monte Carlo value for Pi is 3.141699301 (error 0.00 percent).
Serial correlation coefficient is -0.000009 (totally uncorrelated = 0.0).

Looks pretty good eh? I've attached a picture of the JKISS output I know readers are dying to see. Thanks again.

I've got the main() thing covered. I only presented the code in this fashion for brevity.

Attached Files:

• jkiss32-1gb.png
File size:
318.7 KB
Views:
121
22. Jul 8, 2015

Paul Uszak

I really structure it as:-

Code (Text):

public class JKISS32 {

private int x = 123456789, y = 234567891, z = 345678912, w = 456789123, c = 0, t;

public JKISS32() {
}

public int nextInt() {
y ^= (y << 5);
y ^= (y >>> 7);                    // One > added from PF
y ^= (y << 22);
t = z + w + c;
z = w;
c = (t < 0) ? 1 : 0;               // 1 or 0 ammendment from PF
w = t & 2147483647;
x += 1411392427;
int next = x + y + w;
return next;
}
}

and test as:-

Code (Text):

@Test
public void testRNG() {
System.out.println("Default run");
JKISS32 jk = new JKISS32();

for (int i = 0; i < 20; i++) {
System.out.println(jk.nextInt());
}

assertTrue(true);
}