smlnj / legacy

This project is the old version of Standard ML of New Jersey that continues to support older systems (e.g., 32-bit machines).
BSD 3-Clause "New" or "Revised" License
25 stars 10 forks source link

`Random.realRand` returns far smaller value than unity #290

Closed mmsaito closed 6 months ago

mmsaito commented 6 months ago

Version

110.99.4 (Latest)

Operating System

OS Version

Windows 10

Processor

System Component

SML/NJ Library

Severity

Major

Description

In specification (and the past imprementation) Random.randReal rand returns a number between 0 and 1. But in this version it returns quite smaller values of 4.7x10^-7 at maximum. In addition, the hex image of these number shows the last 20bits are always zero.

Transcript

C:\Users\saitohm\Downloads>sml bugreport_randreal.sml
Standard ML of New Jersey (32-bit) v110.99.4 [built: Tue Aug 01 11:26:46 2023]
[opening bugreport_randreal.sml]
[autoloading]
[library $smlnj/cm/cm.cm is stable]
[library $smlnj/internal/cm-sig-lib.cm is stable]
[library $/pgraph.cm is stable]
[library $smlnj/internal/srcpath-lib.cm is stable]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
[library $c/c.cm is stable]
[library $c/internals/c-int.cm is stable]
[library $c/memory/memory.cm is stable]
[New bindings added.]
val it = true : bool
[autoloading]
[autoloading done]
bugreport_randreal.sml:2.5-2.25 Warning: type vars not generalized because of
   value restriction are instantiated to dummy types (X1,X2,...)
val m = - : (C.double,?.X1) C.obj
val llR8 = fn : real -> Word64.word
val r8LL = fn : Word64.word -> real
[autoloading]
[library $SMLNJ-LIB/Util/smlnj-lib.cm is stable]
[autoloading done]
val rnd = - : Random.rand
val set =
  #[5.38798826666E~08,1.67518343641E~07,1.99236325882E~07,4.45709839036E~07,
   7.95191412717E~09,1.0882304502E~08,2.91691521714E~07,4.17753755477E~07,
   3.8416243342E~07,3.63508757428E~07,1.58076854828E~07,3.99514886507E~07,
   2.60166175936E~07,4.74321876553E~07,2.15442476748E~07,6.6749139549E~09,...]
  : real vector
val rmax = 4.76836801711E~07 : real
val rmin = 7.09876601945E~13 : real
val hex =
  #[0wx3E6CED31D7000000,0wx3E867BE2EF000000,0wx3E8ABDB541800000,
   0wx3E9DE93C9A400000,0wx3E41139C6C000000,0wx3E475E9C34000000,
   0wx3E939338E1200000,0wx3E9C08F472600000,0wx3E99C7DC40000000,
   0wx3E9865086C200000,0wx3E85377AB8400000,0wx3E9ACF9D0D800000,
   0wx3E91759EF1400000,0wx3E9FD4C9ACA00000,0wx3E8CEA8C11000000,
   0wx3E3CAB2540000000,...] : Word64.word vector
-

Expected Behavior

No response

Steps to Reproduce

CM.make "$c\\c.cm";
val m = C.new C.T.double
fun llR8 x = (C.Set.double (Unsafe.cast m,x); C.Get.ulonglong (Unsafe.cast m));
fun r8LL x = (C.Set.ulonglong (Unsafe.cast m,x); C.Get.double (Unsafe.cast m));

val rnd = Random.rand(0,1)
val set = Vector.tabulate(1000000, fn _=> Random.randReal rnd) ; 
val rmax = Vector.foldl Real.max 0.0 set ; 
val rmin = Vector.foldl Real.min 1.0 set ; 
(* val rmax = 4.7683712967E~07 : real 
   val rmin = 7.09876601945E~13 *)

val hex = Vector.map llR8 set;

Additional Information

I haven't see any irregularity in realInt. So, a manual transform from integer to real could mitigate the problem for a meanwhile:

fun randReal rnd = Real.abs((Real.fromInt(Random.randInt rnd) + 0.5)/1073741823.5)

Email address

saitohm@sun.ac.jp

JohnReppy commented 6 months ago

I assume that this issue only affects 32-bit systems? BTW, a more direct way to convert a real number to its bit representation is Unsafe.realToBits.

JohnReppy commented 6 months ago

Looking at the code, there was a typo (wrong constant) in the 32-bit version of the code. Fixed for 110.99.5.

mmsaito commented 6 months ago

Thank you for your prompt work. I've understand that the problem has been fixed and it will be available in the forthcoming version.

Best regards