[ 
https://issues.apache.org/jira/browse/MATH-1300?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15065858#comment-15065858
 ] 

Rostislav Krasny edited comment on MATH-1300 at 12/20/15 6:10 PM:
------------------------------------------------------------------

WELL generators in CM inherite the same nextBytes() of BitsStreamGenerator. 
They extend an AbstractWell that extends the BitsStreamGenerator class. The 
discussed issue of the BitsStreamGenerator#nextBytes() relates to all 
BitsStreamGenerator descendants. I used the MersenneTwister class just for the 
demonstration.

After looking at the Gilles commit I've a few questions:
https://git1-us-west.apache.org/repos/asf?p=commons-math.git;a=commitdiff;h=1d635088f697178660b6e1c9a89d2b7d3bbe2d29

1. Why did you do the change so minimal with many unneded operations still in 
the code instead of taking the code I've proposed? I'm talking about the 
unneded & 0xff operations, not optimal index incrementation and cases where the 
last shift right 8 bits isn't needed. If you think my code is hard to 
understand you may add comments into it. In my opinion this is very simple 
code. Anyway I think the performance is important.

2. I've just noticed the AbstractRandomGenerator has its own implementation of 
the nextBytes() method. Why does it need a differently implemented nextBytes()? 
And why that implementation is so strange? After Gilles commit it's even 
stranger.

before commit:
{code:java}
     @Override
     public void nextBytes(byte[] bytes) {
         int bytesOut = 0;
         while (bytesOut < bytes.length) {
           int randInt = nextInt();
           for (int i = 0; i < 3; i++) {
               if ( i > 0) {
                  randInt >>= 8;
               }
               bytes[bytesOut++] = (byte) randInt;
               if (bytesOut == bytes.length) {
                   return;
               }
           }
         }
     }
{code}
after commit:
{code:java}
     @Override
     public void nextBytes(byte[] bytes) {
         int bytesOut = 0;
         while (bytesOut < bytes.length) {
             int randInt = nextInt();
             for (int i = 0; i < 3; i++) {
                 if (i > 0) {
                     randInt >>= 8;
                 }
             }
             if (bytesOut < bytes.length) {
                 bytes[bytesOut++] = (byte) randInt;
                 if (bytesOut == bytes.length) {
                     return;
                 }
             }
         }
     }
{code}
The original version before commit is not optimized but this is not the only 
issue. It uses only three bytes of the random int, doesn't it? And after Gilles 
commit it uses only one byte of the random int, making many unneeded actions 
around. Both versions of the AbstractRandomGenerator need more calls to 
nextInt() than java.util.Random. Both versions look as a bug.

In my opinion both the BitsStreamGenerator and the AbstractRandomGenerator 
should use the same nextBytes() code that I proposed above.


was (Author: rosti.bsd):
WELL generators in CM inherite the same nextBytes() of BitsStreamGenerator. 
They extend an AbstractWell that extends the BitsStreamGenerator class. The 
discussed issue of the BitsStreamGenerator#nextBytes() relates to all 
BitsStreamGenerator descendants. I used the MersenneTwister class just for the 
demonstration.

After looking at the Gilles commit I've a few questions:
https://git1-us-west.apache.org/repos/asf?p=commons-math.git;a=commitdiff;h=1d635088f697178660b6e1c9a89d2b7d3bbe2d29

1. Why did you do the change so minimal with many unneded operations still in 
the code instead of taking the code I've proposed? I'm talking about the 
unneded & 0xff operations, not optimal index incrementation and cases where the 
last shift right 8 bits isn't needed. If you think my code is hard to 
understand you may add comments into it. In my opinion this is very simple 
code. Anyway I think the performance is important.

2. I've just noticed the AbstractRandomGenerator has its own implementation of 
the nextBytes() method. Why does it need a differently implemented nextBytes()? 
And why that implementation is so strange? After Gilles commit it's even 
stranger.

before commit:
{code:java}
     @Override
     public void nextBytes(byte[] bytes) {
         int bytesOut = 0;
         while (bytesOut < bytes.length) {
           int randInt = nextInt();
           for (int i = 0; i < 3; i++) {
               if ( i > 0) {
                  randInt >>= 8;
               }
               bytes[bytesOut++] = (byte) randInt;
               if (bytesOut == bytes.length) {
                   return;
               }
           }
         }
     }
{code}
after commit:
{code:java}
     @Override
     public void nextBytes(byte[] bytes) {
         int bytesOut = 0;
         while (bytesOut < bytes.length) {
             int randInt = nextInt();
             for (int i = 0; i < 3; i++) {
                 if (i > 0) {
                     randInt >>= 8;
                 }
             }
             if (bytesOut < bytes.length) {
                 bytes[bytesOut++] = (byte) randInt;
                 if (bytesOut == bytes.length) {
                     return;
                 }
             }
         }
     }
{code}
The original version before commit is not optimized but this is not the only 
issue. It uses only three bytes of the random int, doesn't it? And after Gilles 
commit it uses only one byte of the random int, making many unneeded actions 
around. Both version of AbstractRandomGenerator needs more calls to nextInt() 
than java.util.Random. Both versions look as a bug.

In my opinion both the BitsStreamGenerator and the AbstractRandomGenerator 
should use the same nextBytes() code that I proposed above.

> BitsStreamGenerator#nextBytes(byte[]) is wrong
> ----------------------------------------------
>
>                 Key: MATH-1300
>                 URL: https://issues.apache.org/jira/browse/MATH-1300
>             Project: Commons Math
>          Issue Type: Bug
>    Affects Versions: 3.5
>            Reporter: Rostislav Krasny
>         Attachments: MersenneTwister2.java, TestMersenneTwister.java
>
>
> Sequential calls to the BitsStreamGenerator#nextBytes(byte[]) must generate 
> the same sequence of bytes, no matter by chunks of which size it was divided. 
> This is also how java.util.Random#nextBytes(byte[]) works.
> When nextBytes(byte[]) is called with a bytes array of length multiple of 4 
> it makes one unneeded call to next(int) method. This is wrong and produces an 
> inconsistent behavior of classes like MersenneTwister.
> I made a new implementation of the BitsStreamGenerator#nextBytes(byte[]) see 
> attached code.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to