Issue 116920 - Sometimes RND returns 1 (one)
Summary: Sometimes RND returns 1 (one)
Status: CONFIRMED
Alias: None
Product: App Dev
Classification: Unclassified
Component: scripting (show other issues)
Version: 3.3.0 or older (OOo)
Hardware: Unknown Windows, all
: P4 Trivial
Target Milestone: ---
Assignee: AOO issues mailing list
QA Contact:
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-11 07:29 UTC by bormant
Modified: 2017-05-20 11:27 UTC (History)
4 users (show)

See Also:
Issue Type: DEFECT
Latest Confirmation in: ---
Developer Difficulty: ---


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bormant 2011-02-11 07:29:22 UTC
Basic Rnd function SHOULD return pseudorandom value greater or equal than 0 and LESS 
than 1. So, 0 <= Rnd < 1 or [0; 1) interval.

In OpenOffice.org it returns value greater or equal than 0 and LESS OR EQUAL than 1.

Code:
Sub TestRnd
  tries& = 10000000
  s% = 0
  For i& = 1 To tries
    If Rnd = 1 Then s = s + 1
  Next
  MsgBox s / tries
End Sub

Expected result: 0
Result: 3,28E-05 (or near because of random values).

This randomly breaks down an algorithms believing the Rnd value strictly LESS than 1 
with out of bound errors.

Same behaviour in OOo 3.3.0, 3.1.1, 2.4.3.
Comment 1 kay.ramme 2011-02-11 07:52:25 UTC
Andreas, please have a look.
Comment 2 fyva 2011-02-11 09:03:14 UTC
Please, consider this along with issue 14730
Comment 3 fyva 2011-02-12 10:49:26 UTC
This seems to be Windows OS problem. On Linux the macro above gives 0.
Comment 4 bormant 2011-02-13 12:08:43 UTC
I can not reproduce this bug on 32-bit linux biulds of OOo (tested on Slackware-
13.1, Fedora-14, Ubuntu-10.04).
So, OS field has been changed to Windows.

I can not agree that the problem is OS, not the OOo build for Windows.

The Linux Programmers Guide says that the rand() function returns a pseudo-
random integer in the range [0, RAND_MAX]. MSDN has similar description.

Current OOo Basic RND implementation doesn't contain any differences for 
Win/Lin:

basic/source/runtime/methods.cxx

 RTLFUNC(Rnd)
 {
     (void)pBasic;
     (void)bWrite;
 
 	if ( rPar.Count() > 2 )
 		StarBASIC::Error( SbERR_BAD_ARGUMENT );
 	else
 	{
 		double nRand = (double)rand();
 		nRand = ( nRand / (double)RAND_MAX );
 		rPar.Get(0)->PutDouble( nRand );
 	}
}

So, the only reason is used C/C++ compiler runtime: rand() returns [0;RAND_MAX) 
on Linux and [0;RAND_MAX] on Windows.

May be (quick and dirty)

#IFDEF (<something_unique_for_this_win_compiler>)
                // srand() returns [0;RAND_MAX]
 		nRand = ( nRand / ((double)RAND_MAX + 1.));
#ELSE
                // srand() returns [0;RAND_MAX)
 		nRand = ( nRand / (double)RAND_MAX );
#ENDIF

32766/32767 = 0,999969481
32766/32768 = 0,999938965
32767/32768 = 0,999969482

And if we can agree with maximum RND values 0,999938965 on Linux and 0,999969482 
on Windows, too more dirty:

 		nRand = ( nRand / ((double)RAND_MAX + 1.));
Comment 5 Regina Henschel 2011-02-13 13:39:05 UTC
ScRandom() in interpr1.cxx has been changed to return values from [0;1[ with
issue 53642. I think, that Basic should return the same range as Calc.
ScRandom() uses  PushDouble((double)rand() / ((double)RAND_MAX+1.0));

For VB you find the description "The Rnd function returns a value less than 1,
but greater than or equal to zero."
[http://msdn.microsoft.com/en-us/library/f7s023d2(VS.90).aspx#Y1057]
Comment 6 bormant 2011-02-13 13:58:19 UTC
So, for 32 bit int 

2147483646 / 2147483647	= 0,9999999995
2147483646 / 2147483648	= 0,9999999991
2147483647 / 2147483648	= 0,9999999995

and 
	else 	
	{
		double nRand = (double)rand();
		nRand = ( nRand / (double)RAND_MAX );
		rPar.Get(0)->PutDouble( nRand );
	}

can be simple replaceced with 
	else 	
		rPar.Get(0)->PutDouble( (double)rand() / ((double)RAND_MAX + 1. 
)
Comment 7 bormant 2011-02-13 14:01:40 UTC
else
  rPar.Get(0)->PutDouble( (double)rand() / ((double)RAND_MAX + 1.) );
Comment 8 bormant 2011-02-13 14:22:56 UTC
http://msdn.microsoft.com/en-us/library/398ax69y.aspx says, that MS VC 2010 still 
use 32767 as RAND_MAX for rand().

If this is true, we get
32767/32768 = 0,999969482 max with 1/32768 granularity on Windows,
2147483647/2147483648=0,9999999995 max with 1/2147483648 granularity on Linux.

It is even slightly better than it was :-) .

So, (double)rand()/((double)RAND_MAX+1.) is good enough.
Comment 9 fyva 2011-02-14 13:40:12 UTC
bormant, you mean that this issue affects not only Windows, just it happens very
rarely? I.e., if you run the macro in OP with 10 000 000 replaced by, e.g.,
something more than 2147483647 ? Then this fix would fit for all OSes.
Comment 10 Marcus 2017-05-20 11:27:37 UTC
Reset assigne to the default "issues@openoffice.apache.org".