multicloud365
  • Home
  • Cloud Architecture
    • OCI
    • GCP
    • Azure
    • AWS
    • IAC
    • Cloud Networking
    • Cloud Trends and Innovations
    • Cloud Security
    • Cloud Platforms
  • Data Management
  • DevOps and Automation
    • Tutorials and How-Tos
  • Case Studies and Industry Insights
    • AI and Machine Learning in the Cloud
No Result
View All Result
  • Home
  • Cloud Architecture
    • OCI
    • GCP
    • Azure
    • AWS
    • IAC
    • Cloud Networking
    • Cloud Trends and Innovations
    • Cloud Security
    • Cloud Platforms
  • Data Management
  • DevOps and Automation
    • Tutorials and How-Tos
  • Case Studies and Industry Insights
    • AI and Machine Learning in the Cloud
No Result
View All Result
multicloud365
No Result
View All Result

Implementing xoshiro256** in PL/SQL – Sean D. Stuber

admin by admin
April 6, 2025
in OCI
0
Creation of Code 2024 – Day 1
399
SHARES
2.3k
VIEWS
Share on FacebookShare on Twitter


A very long time in the past I ported the Mersenne Tornado pseudo-random quantity generator to pl/sql. That algorithm, and my port, are displaying their age so I began different mills. A more moderen method is discovered within the xoshiro/xoroshiro household by David Blackman and Sebastiano Vigna discovered right here.

I’ve chosen xoshiro256** as certainly one of their “all-purpose, rock-solid
mills”
. Just like the Mersenne Tornado, the unique supply is written in c and makes use of quite a few bit manipulations to generate new values from the prior ones.

Whereas PL/SQL has the BITAND operate, it doesn’t have any others that immediately apply to numeric sorts. It could have been attainable to make use of RAW values and the UTL_RAW bundle, however I discovered it simpler to maintain true to the unique implementation by creating my very own bit-wise OR, XOR, shift, and rotation capabilities.

Implementing 64-bit integer subtype (virtually)

One other complexity is that c has the uint64_t kind. That’s, a 64-bit unsigned integer. Whereas PL/SQL NUMBER sorts can maintain such values, their is not any direct correlation. Ideally I’d create an integer subtype constrained with a RANGE clause of 0..18446744073709551615 (2^64-1). Nonetheless, there isn’t a authorized syntax to assist that definition. As of 23ai, the RANGE clause solely applies to subtypes of PLS_INTEGER which is, itself, restricted to signed 32-bit values. So I settled for a 20-digit integer utilizing:

SUBTYPE uint64_t IS NUMBER(20, 0)

Then, in my calculations I apply a 64-bit masks to make sure overflows are dealt with in a approach that mimics the c uint64_t.

Bit-wise operators

As talked about above, among the c syntax has no corresponding pl/sql operator or operate. Specifically:

  • | – OR
  • ^ – XOR
  • >> – Shift proper

Luckily, BITAND and arithmetic is enough to create OR and XOR. Multiplying or dividing by powers of two will replicate bit shifts left or proper respectively.

    FUNCTION bitor(p_a IN uint64_t, p_b IN uint64_t)
        RETURN uint64_t
    IS
    BEGIN
        RETURN BITAND(p_a + p_b - BITAND(p_a, p_b), c_64bitmask);
    END bitor;

    FUNCTION bitxor(p_a IN uint64_t, p_b IN uint64_t)
        RETURN uint64_t
    IS
    BEGIN
        RETURN BITAND((p_a + p_b) - (BITAND(p_a, p_b) * 2), c_64bitmask);
    END bitxor;

    FUNCTION shl64(p_n IN uint64_t, p_bits IN bits_t)
        RETURN uint64_t
    IS
    BEGIN
        -- Apply 64-bit masks to make sure outcomes are inside correct vary
        RETURN CASE p_bits WHEN 0 THEN p_n ELSE BITAND(p_n * (2 ** p_bits), c_64bitmask) END;
    END shl64;

    FUNCTION shr64(p_n IN uint64_t, p_bits IN bits_t)
        RETURN uint64_t
    IS
    BEGIN
        -- Apply 64-bit masks to make sure outcomes are inside correct vary
        RETURN CASE p_bits WHEN 0 THEN p_n ELSE BITAND(p_n / (2 ** p_bits), c_64bitmask) END;
    END shr64;

It wasn’t technically essential to make use of a CASE for shifts of 0 bits, nevertheless it appeared extra pure to seize that particular case fairly than pressure the additional math steps to provide a consequence we already knew. That is merely a choice on my half and each shl64 and shr64 could possibly be simplified to let 0 run the identical as some other shift worth. Additionally of observe, each of the shift capabilities apply the 64-bit masks to make sure there the outcomes at all times fall within the supposed 0-18446744073709551615 vary.

The final particular bit operation is rotation, the xoshiro code itself consists of the rotl logic which might then be transformed to PL/SQL utilizing the capabilities above:

    FUNCTION rotl(p_x uint64_t, p_k IN bits_t)
        RETURN uint64_t
    IS
    -- static inline uint64_t rotl(const uint64_t x, int okay) {
    --  return (x > (64 - okay));
    -- }
    BEGIN
        RETURN CASE WHEN p_k = 0 THEN p_x ELSE bitor(shl64(p_x, p_k), shr64(p_x, 64 - p_k)) END;
    END rotl;

Pulling all of it collectively

With the bit operations set, implementing the capabilities was pretty straight ahead. There are a number of arrays used throughout the unique c code which I initially applied as varrays, nevertheless it felt synthetic to maintain adjusting the varray indexes to be 1-based vs the 0-based arrays. So, as a substitute, I made a decision to make use of an associative arrays with indexes restricted to 0,1,2,3. The total bundle follows:

CREATE OR REPLACE PACKAGE xoshiro256
IS
    -- Based mostly on xoshiro256** by by David Blackman and Sebastiano Vigna
    -- unique  https://prng.di.unimi.it/xoshiro256starstar.c


    --                    .///.
    --                   (0 o)
    ---------------0000--(_)--0000---------------
    --
    --  Sean D. Stuber
    --  sean.stuber@gmail.com
    --
    --             oooO      Oooo
    --------------(   )-----(   )---------------
    --              (       ) /
    --              _)     (_/


    -- It could be good to outline an express RANGE 0.. 18446744073709551615  for the subtype
    -- however as of 23ai, solely subtypes of PLS_INTEGER might have a variety.
    SUBTYPE uint64_t IS NUMBER(20, 0);

    TYPE seed_tab IS TABLE OF uint64_t;

    PROCEDURE set_state(p_seed IN seed_tab);

    FUNCTION get_next
        RETURN uint64_t;

    PROCEDURE bounce;

    PROCEDURE long_jump;
END;
CREATE OR REPLACE PACKAGE BODY sds.xoshiro256
IS
    -- TO_NUMBER('ffffffffffffffff', 'xxxxxxxxxxxxxxxx') = 18446744073709551615 = 2^64-1
    c_64bitmask   CONSTANT uint64_t := POWER(2, 64) - 1; -- 18446744073709551615

    SUBTYPE bits_t IS PLS_INTEGER RANGE 0 .. 63;

    SUBTYPE array_index_t IS PLS_INTEGER RANGE 0 .. 3;

    TYPE state_array_t IS TABLE OF uint64_t
        INDEX BY array_index_t;

    g_state                 state_array_t;

    FUNCTION bitor(p_a IN uint64_t, p_b IN uint64_t)
        RETURN uint64_t
    IS
    BEGIN
        RETURN BITAND(p_a + p_b - BITAND(p_a, p_b), c_64bitmask);
    END bitor;

    FUNCTION bitxor(p_a IN uint64_t, p_b IN uint64_t)
        RETURN uint64_t
    IS
    BEGIN
        RETURN BITAND((p_a + p_b) - (BITAND(p_a, p_b) * 2), c_64bitmask);
    END bitxor;

    FUNCTION shl64(p_n IN uint64_t, p_bits IN bits_t)
        RETURN uint64_t
    IS
    BEGIN
        -- Apply 64-bit masks to make sure outcomes are inside correct vary
        RETURN CASE p_bits WHEN 0 THEN p_n ELSE BITAND(p_n * (2 ** p_bits), c_64bitmask) END;
    END shl64;

    FUNCTION shr64(p_n IN uint64_t, p_bits IN bits_t)
        RETURN uint64_t
    IS
    BEGIN
        -- Apply 64-bit masks to make sure outcomes are inside correct vary
        RETURN CASE p_bits WHEN 0 THEN p_n ELSE BITAND(p_n / (2 ** p_bits), c_64bitmask) END;
    END shr64;

    FUNCTION rotl(p_x uint64_t, p_k IN bits_t)
        RETURN uint64_t
    IS
    -- static inline uint64_t rotl(const uint64_t x, int okay) {
    --  return (x > (64 - okay));
    -- }
    BEGIN
        RETURN CASE WHEN p_k = 0 THEN p_x ELSE bitor(shl64(p_x, p_k), shr64(p_x, 64 - p_k)) END;
    END rotl;

    FUNCTION get_next
        RETURN uint64_t
    IS
        --  uint64_t subsequent(void) {
        --   const uint64_t consequence = rotl(s[1] * 5, 7) * 9;
        --
        --   const uint64_t t = s[1]  TO_NUMBER('180ec6d33cfd0aba', 'xxxxxxxxxxxxxxxx'),
                            1   => TO_NUMBER('d5a61266f0c9392c', 'xxxxxxxxxxxxxxxx'),
                            2   => TO_NUMBER('a9582618e03fc9aa', 'xxxxxxxxxxxxxxxx'),
                            3   => TO_NUMBER('39abdc4529b1661c', 'xxxxxxxxxxxxxxxx')) ;

        v_s0              uint64_t := 0;
        v_s1              uint64_t := 0;
        v_s2              uint64_t := 0;
        v_s3              uint64_t := 0;
        v_dummy           uint64_t;
    BEGIN
        FOR i IN 0 .. 3
        LOOP
            FOR b IN 0 .. 63
            LOOP
                IF BITAND(v_jump(i), shl64(1, b)) != 0
                THEN
                    v_s0 := bitxor(v_s0, g_state(0));
                    v_s1 := bitxor(v_s1, g_state(1));
                    v_s2 := bitxor(v_s2, g_state(2));
                    v_s3 := bitxor(v_s3, g_state(3));
                END IF;

                v_dummy := get_next;
            END LOOP;
        END LOOP;

        g_state(0) := v_s0;
        g_state(1) := v_s1;
        g_state(2) := v_s2;
        g_state(3) := v_s3;
    END bounce;

    PROCEDURE long_jump
    IS
        --  /* That is the long-jump operate for the generator. It's equal to
        --     2^192 calls to subsequent(); it may be used to generate 2^64 beginning factors,
        --     from every of which bounce() will generate 2^64 non-overlapping
        --     subsequences for parallel distributed computations. */
        --
        --  void long_jump(void) {
        --   static const uint64_t LONG_JUMP[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 };
        --
        --   uint64_t s0 = 0;
        --   uint64_t s1 = 0;
        --   uint64_t s2 = 0;
        --   uint64_t s3 = 0;
        --   for(int i = 0; i  TO_NUMBER('76e15d3efefdcbbf', 'xxxxxxxxxxxxxxxx'),
                            1   => TO_NUMBER('c5004e441c522fb3', 'xxxxxxxxxxxxxxxx'),
                            2   => TO_NUMBER('77710069854ee241', 'xxxxxxxxxxxxxxxx'),
                            3   => TO_NUMBER('39109bb02acbe635', 'xxxxxxxxxxxxxxxx')) ;

        v_s0                  uint64_t := 0;
        v_s1                  uint64_t := 0;
        v_s2                  uint64_t := 0;
        v_s3                  uint64_t := 0;
        v_dummy               uint64_t;
    BEGIN
        FOR i IN 0 .. 3
        LOOP
            FOR b IN 0 .. 63
            LOOP
                IF BITAND(v_longjump(i), shl64(1, b)) != 0
                THEN
                    v_s0 := bitxor(v_s0, g_state(0));
                    v_s1 := bitxor(v_s1, g_state(1));
                    v_s2 := bitxor(v_s2, g_state(2));
                    v_s3 := bitxor(v_s3, g_state(3));
                END IF;

                v_dummy := get_next;
            END LOOP;
        END LOOP;

        g_state(0) := v_s0;
        g_state(1) := v_s1;
        g_state(2) := v_s2;
        g_state(3) := v_s3;
    END long_jump;

    PROCEDURE set_state(p_seed IN seed_tab)
    IS
    BEGIN
        g_state := state_array_t();

        FOR i IN 0 .. 3
        LOOP
            g_state(i) := p_seed(i + 1);
        END LOOP;
    END set_state;
END;

Choosing a set of fine seed values assist construct higher distributions within the generated sequence. For the needs of illustration although, I’ll use a easy 12345 in every of the seed array components after which generate 10 values with get_next, then bounce and generate 10 extra and at last do a long_jump and generate a last set of 10. This easy framework allowed me to confirm my logic in opposition to the unique doing the identical steps.

DECLARE
    x   xoshiro256.uint64_t;
BEGIN
    xoshiro256.set_state(xoshiro256.seed_tab(12345, 12345, 12345, 12345));

    FOR i IN 0 .. 9
    LOOP
        x := xoshiro256.get_next;
        DBMS_OUTPUT.put_line(TO_CHAR(i, '9') || ' ' || LPAD(TO_CHAR(x), 20) || ' ' || TO_CHAR(x, 'xxxxxxxxxxxxxxxx'));
    END LOOP;

    DBMS_OUTPUT.put_line('--- bounce ---');
    xoshiro256.bounce;

    FOR i IN 0 .. 9
    LOOP
        x := xoshiro256.get_next;
        DBMS_OUTPUT.put_line(TO_CHAR(i, '9') || ' ' || LPAD(TO_CHAR(x), 20) || ' ' || TO_CHAR(x, 'xxxxxxxxxxxxxxxx'));
    END LOOP;

    DBMS_OUTPUT.put_line('--- lengthy bounce ---');
    xoshiro256.long_jump;

    FOR i IN 0 .. 9
    LOOP
        x := xoshiro256.get_next;
        DBMS_OUTPUT.put_line(TO_CHAR(i, '9') || ' ' || LPAD(TO_CHAR(x), 20) || ' ' || TO_CHAR(x, 'xxxxxxxxxxxxxxxx'));
    END LOOP;
END;

This produced the next sequences…

0             71107200           43d0280
1             71107200           43d0280
2        9320162918400       87a05000000
3        9320234025600       87a093d0280
4 12773345438245847175  b1440a0000000087
5 12768617581213858983  b1333e0a010f3ca7
6  8945543092777141728  7c24f40c1fee45e0
7   470016407425146078   685d56eab2e5cde
8  3493524090943047400  307b7da6b6ee06e8
9  5886979323815290452  51b2c08124146654
--- bounce ---
0  4581861990845984958  3f960b34763d30be
1  6555207914207083891  5af8c6ddf3247d73
2  1155739510168040853  100a02f60c733595
3 17756807916997691290  f66cdab88d7dc79a
4 18120637618276044033  fb796fe814ec8d01
5  3601654045701872973  31fba545ade89d4d
6  1200605674697995402  10a9688003b1348a
7  2838098080646629052  2762f32adea906bc
8 13449286687953663012  baa576fc3dde3424
9  5139522055796585030  47534014530a7246
--- lengthy bounce ---
0   308148744041885595   446c3a66a996f9b
1  1534996402541018053  154d671868f5bbc5
2  2575119349696104759  23bca967acdf0937
3  1204256562158620046  10b660f67de5cd8e
4  2485655289488877646  227ed250f40e284e
5  2705313921121906326  258b34ad8a63ee96
6 14047681829789752210  c2f364324653db92
7  8712759958851592880  78e9f1053898a2b0
8 16323705335360483007  e28973840c4f6ebf
9  2581999948191718881  23d51b45da0b5de1

This was a enjoyable little train. Finally I’d prefer to increase on it to implement different variations within the xoshiro/xoroshiro suite in addition to embrace assist for splitmix64 as a approach to assist begin with higher seed values.

Questions and feedback, as at all times, are welcome.

Tags: ImplementingPLSQLSeanStuberxoshiro256
Previous Post

Grasp Information Administration with Giant Language Fashions | by Akash Rawat | Apr, 2025

Next Post

Improve Pipeline Safety with Workload Id Federation: A Complete Information | by Jack Roper

Next Post
Improve Pipeline Safety with Workload Id Federation: A Complete Information | by Jack Roper

Improve Pipeline Safety with Workload Id Federation: A Complete Information | by Jack Roper

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Trending

An Overview of IBM Bluemix

An Overview of IBM Bluemix

May 2, 2025
Past open vs. closed: Understanding the spectrum of AI transparency

Past open vs. closed: Understanding the spectrum of AI transparency

March 22, 2025
Getting Began with .NET: Understanding its Fundamentals and Use Instances

Getting Began with .NET: Understanding its Fundamentals and Use Instances

May 7, 2025
Predominant kinds of Machine Studying – 2 | by Karim Samir | simplifyai | Apr, 2025

Predominant kinds of Machine Studying – 2 | by Karim Samir | simplifyai | Apr, 2025

April 8, 2025
Get Lifetime 1TB of Cloud Storage for Simply $130

Get Lifetime 1TB of Cloud Storage for Simply $130

January 24, 2025
Repurposing Protein Folding Fashions for Era with Latent Diffusion – The Berkeley Synthetic Intelligence Analysis Weblog

Repurposing Protein Folding Fashions for Era with Latent Diffusion – The Berkeley Synthetic Intelligence Analysis Weblog

April 10, 2025

MultiCloud365

Welcome to MultiCloud365 — your go-to resource for all things cloud! Our mission is to empower IT professionals, developers, and businesses with the knowledge and tools to navigate the ever-evolving landscape of cloud technology.

Category

  • AI and Machine Learning in the Cloud
  • AWS
  • Azure
  • Case Studies and Industry Insights
  • Cloud Architecture
  • Cloud Networking
  • Cloud Platforms
  • Cloud Security
  • Cloud Trends and Innovations
  • Data Management
  • DevOps and Automation
  • GCP
  • IAC
  • OCI

Recent News

Safe & Environment friendly File Dealing with in Spring Boot: Learn, Write, Compress, and Defend | by Rishi | Mar, 2025

Safe & Environment friendly File Dealing with in Spring Boot: Learn, Write, Compress, and Defend | by Rishi | Mar, 2025

May 15, 2025
Bitwarden vs Dashlane: Evaluating Password Managers

Bitwarden vs Dashlane: Evaluating Password Managers

May 15, 2025
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact

© 2025- https://multicloud365.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Cloud Architecture
    • OCI
    • GCP
    • Azure
    • AWS
    • IAC
    • Cloud Networking
    • Cloud Trends and Innovations
    • Cloud Security
    • Cloud Platforms
  • Data Management
  • DevOps and Automation
    • Tutorials and How-Tos
  • Case Studies and Industry Insights
    • AI and Machine Learning in the Cloud

© 2025- https://multicloud365.com/ - All Rights Reserved