Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0002112Core InformPhrases and functional programmingpublic2019-10-25 19:482019-10-27 21:07
Reporterotistdog 
Assigned To 
PrioritynormalSeverityseriousReproducibilityalways
StatusnewResolutionopen 
Platformx86OSWindowsOS Version7
Product Version6M62 
Target VersionFixed in Version 
Summary0002112: Requesting a random real number generates incomplete/incorrect I6 code
DescriptionThe sample code provided below generates a "Translating the Source - Failed" message.

The console output from the compilation process (see additional information for full text) produces an error message:

  auto.inf(11870): Error: No such constant as "R_REAL_NUMBER_TY_Say"

I'm not sure if the relevant I7 code here is improper or not. I don't see any specific examples in WWI or RB that use "a random real number...", but experimentation shows that choosing a random real-based kind of arithmetic value will work. (See commented out section in example code.) The issue seems specific to using the real number kind.

Looking at the generated I6 code, it almost looks like the I7 compiler wanted to call a function with the right structure but somehow generated the wrong function name at that point.
Minimal Source Text To Reproduce
"R_REAL_NUMBER_TY_Say Issue"

Place is a room.

When play begins:
	let X be a random real number between 1.0 and 3.0;
	say "X = [X]."

[The following code works as expected, which implies that the above should work.]
[A fakereal is a kind of value. 1.0 fake specifies a fakereal.

When play begins:
	let X be a random fakereal between 2.0 fake and 3.0 fake;
	say "X = [X]."]
Additional InformationFull text of console output:
----------------------------------
Inform 7 build 6M62 has started.
I've now read your source text, which is 28 words long.
I've also read Standard Rules by Graham Nelson, which is 42655 words long.
I've also read English Language by Graham Nelson, which is 2297 words long.

  The 28-word source text has successfully been translated into an intermediate
    description which can be run through Inform 6 to complete compilation.
    There were 1 room and 1 thing.
Inform 7 has finished.

C:\Program Files (x86)\Inform 7\Compilers\inform6 \
    -wSDG +include_path=..\Source,.\ auto.inf output.ulx
Inform 6.33N for Win32 (30th August 2015)
In: 1 source code files 66462 syntactic lines
 56110 textual lines 2054316 characters (ISO 8859-1 Latin1)
Allocated:
  8066 symbols (maximum 20000) 13802404 bytes of memory
Out: Glulx story file 1.191025 (586K long):
    21 classes (maximum 200) 42 objects (maximum 640)
   230 global vars (maximum 512) 85099 variable/array space (maximum 180000)
    96 verbs (maximum 255) 316 dictionary entries (maximum 2000)
   179 grammar lines (version 2) 251 grammar tokens (unlimited)
   101 actions (maximum 200) 37 attributes (maximum 56)
    40 common props (maximum 256) 18 individual props (unlimited)
108980 characters used in text 85433 bytes compressed (rate 0.783)
     0 abbreviations (maximum 64) 2887 routines (unlimited)
 69553 instructions of code 39309 sequence points
105472 bytes writable memory used 494336 bytes read-only memory used
599808 bytes used in machine 1073142016 bytes free in machine
auto.inf(11870): Error: No such constant as "R_REAL_NUMBER_TY_Say"
Compiled with 1 error and 1650 suppressed warnings
Completed in 1 seconds

Compiler finished with code 1
----------------------------------



Specific I6 code block for line referred to in the error message:
----------------------------------
! Rules in rulebook: When play begins (B4_when_play_begins)
! ----------------------------------------------------------------------------------------------------
! Rule 1/1 ! When play begins:
! ----------------------------------------------------------------------------------------------------
! No specific request
! When play begins:
[ R_799
    tmp_0 ! Let/loop value, e.g., 'X': real number
    ;
    if (debug_rules) DB_Rule(R_799, 799);
    ! [2: let x be a random real number between 1.0 and 3.0]

     tmp_0 = R_REAL_NUMBER_TY_Say(1065353216, 1077936128);
    ! [3: say ~X = [X].~]
    say__p=1;! [4: ~X = ~]
    ParaContent(); print "X = ";! [5: x]
    ParaContent(); REAL_NUMBER_TY_Say(tmp_0);! [6: ~.~]
    ParaContent(); print "."; new_line; .L_Say1; .L_SayX1;rfalse;
];
----------------------------------
TagsNo tags attached.
Effect(critical) Inform 6 compiler reports errors for valid code
Attached Files

- Relationships

-  Notes
(0004888)
zarf (developer)
2019-10-26 12:00

I think the code is not valid. There's no implementation in the I6 template layer for generating a random real number with a flat distribution (or any other distribution).

Your example with fakereal compiles, but it doesn't work correctly. It winds up using an integer random-number routine and then interpreting the result as a real. The result doesn't have a flat distribution. You can see this if you try:

let X be a random fakereal between 1.0 fake and 1000.0 fake;

The results are strongly biased towards small numbers, because of the way floats are encoded.
(0004889)
zarf (developer)
2019-10-26 12:04

Conclusion: the compiler should throw an error message for both of the above code examples.

To get what you want, you can do this:

let N be a random number between 0 and 999;
let X be 1.0 + ( N * 0.002 );

This isn't a true random float, since it can only produce 1000 distinct real values, but it probably covers your needs.
(0004890)
NYKevin (reporter)
2019-10-27 21:07

If for some reason you need a more precise random float, I would do something like this:

Let N be a random number between 0 and 16777216;
Let X be N / 16777216.0;

This will produce a value uniformly distributed on the closed interval [0.0, 1.0] (which may then be multiplied or added to as needed), and unlike choosing arbitrary coefficients, it produces the maximum possible precision without any rounding bias (assuming IEEE 754 binary32, see WI 15.3). It does neglect rather a lot of small numbers, and progressively fewer and fewer numbers as you get closer to one. This is because the floating-point numbers are much denser around zero than around one, so we have to choose between ignoring most of the numbers close to zero, and finding some way of assigning them much lower probability weights. The latter is hard, and the former is easy.

Note also that it is not safe to use a larger number than 16777216 for this purpose. 16777217.0 is not a floating-point number, so if N is given the value 16777217, it will get rounded down to 16777216.0 or up to 16777218.0, and either of those will bias the result. So we should not allow N to be 16777217 or any larger odd number, which puts an upper limit on our choice of random values.

The Right Way to do this is to calculate the exponent and significand separately, using some kind of skewed exponential-ish distribution for the former, but I'm not sure if there's a reasonable way to do that in Inform 7. I'm also not sure the extra precision actually helps when you're going for a uniform distribution anyway. 24 bits should be enough precision for most practical applications.

- Issue History
Date Modified Username Field Change
2019-10-25 19:48 otistdog New Issue
2019-10-26 12:00 zarf Note Added: 0004888
2019-10-26 12:04 zarf Note Added: 0004889
2019-10-27 21:07 NYKevin Note Added: 0004890


Copyright © 2000 - 2010 MantisBT Group
Powered by Mantis Bugtracker