[GRASS-dev] r.mapcal rand() strangeness

Glynn Clements glynn at gclements.plus.com
Sun Feb 24 00:03:49 EST 2008


Maciej Sieczka wrote:

> $ r.mapcalc 'map=rand(-2147483648,2147483647)'
> 
> $ r.stats -1 map | sort -n | uniq
>   100%
> -2147483647
> -2147483646
> 
> Why only 2 values from 4294967295 possible? Region is big enough to 
> accomodate more than 2 values from the range:

	res[i] = (lo == hi) ? lo : lo + x % (hi - lo);

The expression (hi - lo) is overflowing the range of a signed integer.

Also, x will be restricted to 0 <= x < 2^31, possibly less if the
system doesn't have lrand48().

The wrapping can be fixed by adding casts, i.e.:

	res[i] = (lo == hi) ? lo : lo + (unsigned) x % (unsigned) (hi - lo);

The 31-bit limitation can be fixed by replacing lrand48() with
mrand48(), which covers the full (signed) 32-bit range.

The attached patch appears to work.

One final point: -2^31 (= 0x80000000 = -2147483648) is the null value
for the CELL type, so you'll never see that value in a map.

-- 
Glynn Clements <glynn at gclements.plus.com>

-------------- next part --------------
Index: raster/r.mapcalc/xrand.c
===================================================================
--- raster/r.mapcalc/xrand.c	(revision 30316)
+++ raster/r.mapcalc/xrand.c	(working copy)
@@ -13,7 +13,7 @@
 
 #if !defined(HAVE_DRAND48)
 #define drand48() ((double)rand()/((double)RAND_MAX + 1))
-#define lrand48() ((long)rand())
+#define mrand48() ((long)rand())
 #endif
 
 int 
@@ -35,11 +35,11 @@
 		CELL *arg2 = args[2];
 		for (i = 0; i < columns; i++)
 		{
-			long x = lrand48();
+			unsigned long x = (unsigned long) mrand48();
 			int lo = arg1[i];
 			int hi = arg2[i];
 			if (lo > hi) { int tmp = lo; lo = hi; hi = tmp; }
-			res[i] = (lo == hi) ? lo : lo + x % (hi - lo);
+			res[i] = (lo == hi) ? lo : lo + x % (unsigned long) (hi - lo);
 		}
 		return 0;
 	}


More information about the grass-dev mailing list