Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-26 09:34:38

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // SPDX-FileCopyrightText: 2020 CERN
0003 // SPDX-FileCopyrightText: 2025 Celeritas contributors
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 /*!
0007  * \file corecel/random/engine/detail/RanluxppImpl.hh
0008  *
0009  * Original source:
0010  * https://github.com/apt-sim/AdePT/blob/master/include/AdePT/copcore/ranluxpp/helpers.h
0011  * and
0012  * https://github.com/apt-sim/AdePT/blob/master/include/AdePT/copcore/ranluxpp/mulmod.h
0013  * and
0014  * https://github.com/apt-sim/AdePT/blob/master/include/AdePT/copcore/ranluxpp/ranlux_lcg.h
0015  */
0016 //---------------------------------------------------------------------------//
0017 #pragma once
0018 
0019 #include "corecel/cont/Range.hh"
0020 #include "corecel/cont/Span.hh"
0021 #include "corecel/math/NumericLimits.hh"
0022 #include "corecel/random/data/RanluxppTypes.hh"
0023 
0024 namespace celeritas
0025 {
0026 namespace detail
0027 {
0028 
0029 // Compute a + b and set overflow accordingly
0030 inline CELER_FUNCTION RanluxppUInt add_overflow(
0031     RanluxppUInt a, RanluxppUInt b, unsigned int& overflow);
0032 
0033 // Compute a + b and increment carry if there was an overflow
0034 inline CELER_FUNCTION RanluxppUInt add_carry(
0035     RanluxppUInt a, RanluxppUInt b, unsigned int& carry);
0036 
0037 // Compute a - b` and set overflow accordingly
0038 inline CELER_FUNCTION RanluxppUInt sub_overflow(
0039     RanluxppUInt a, RanluxppUInt b, unsigned int& overflow);
0040 
0041 // Compute a - b and increment `carry` if there was an overflow
0042 inline CELER_FUNCTION RanluxppUInt sub_carry(
0043     RanluxppUInt a, RanluxppUInt b, unsigned int& carry);
0044 
0045 // Update r = r - (t1 + t2) + (t3 + t2) * b ** 10
0046 inline CELER_FUNCTION int64_t compute_remainder(
0047     Span<RanluxppUInt const, 9> upper, Span<RanluxppUInt, 9> r);
0048 
0049 // Multiply two 576 bit numbers, stored as 9 numbers of 64 bits each
0050 [[nodiscard]] inline CELER_FUNCTION RanluxppArray18 multiply_9x9(
0051     RanluxppArray9 const& in1, RanluxppArray9 const& in2);
0052 
0053 // Compute a value congruent to mul modulo m less than 2 ** 576
0054 [[nodiscard]] inline CELER_FUNCTION RanluxppArray9 compute_modulus(
0055     RanluxppArray18 const& mul);
0056 
0057 // Combine multiply9x9 and mod_m with internal temporary storage
0058 [[nodiscard]] inline CELER_FUNCTION RanluxppArray9 compute_mod_multiply(
0059     RanluxppArray9 const& factor1, RanluxppArray9 const& factor2);
0060 
0061 // Compute base to the 2^n modulo m
0062 [[nodiscard]] inline CELER_FUNCTION RanluxppArray9 compute_power_exp_modulus(
0063     RanluxppArray9 base, RanluxppUInt log_n);
0064 
0065 // Compute base to the n modulo m
0066 [[nodiscard]] inline CELER_FUNCTION RanluxppArray9 compute_power_modulus(
0067     RanluxppArray9 base, RanluxppUInt n);
0068 
0069 // Convert RANLUX numbers to an LCG state
0070 [[nodiscard]] inline CELER_FUNCTION RanluxppArray9 to_lcg(
0071     RanluxppNumber const& ranlux);
0072 
0073 // Convert an LCG state to RANLUX numbers
0074 [[nodiscard]] inline CELER_FUNCTION RanluxppNumber to_ranlux(
0075     RanluxppArray9 const& lcg);
0076 
0077 //---------------------------------------------------------------------------//
0078 // INLINE FUNCTION DEFINITIONS
0079 //---------------------------------------------------------------------------//
0080 /*!
0081  * Compute sum of \p a and \p b and set \p overflow accordingly.
0082  *
0083  * \param[in]  a         The first operand of the sum
0084  * \param[in]  b         The second operand of the sum
0085  * \param[out] overflow  The amount of (potential) overflow
0086  *
0087  * \return The result of the sum
0088  */
0089 CELER_FUNCTION RanluxppUInt add_overflow(
0090     RanluxppUInt a, RanluxppUInt b, unsigned int& overflow)
0091 {
0092     RanluxppUInt add = a + b;
0093     overflow = (add < a);
0094     return add;
0095 }
0096 
0097 //---------------------------------------------------------------------------//
0098 /*!
0099  * Compute sum of \p a and \p b and increment \p carry if there was an
0100  * overflow.
0101  *
0102  * \param[in]  a      The first operand of the sum
0103  * \param[in]  b      The second operand of the sum
0104  * \param[out] carry  Maintains sum of all overflows
0105  *
0106  * \return The result of the sum
0107  */
0108 CELER_FUNCTION RanluxppUInt add_carry(
0109     RanluxppUInt a, RanluxppUInt b, unsigned int& carry)
0110 {
0111     unsigned int overflow;
0112     RanluxppUInt add = add_overflow(a, b, overflow);
0113 
0114     // Do NOT branch on overflow to avoid jumping code, just add 0 if there was
0115     // no overflow.
0116     carry += overflow;
0117     return add;
0118 }
0119 
0120 //---------------------------------------------------------------------------//
0121 /*!
0122  * Compute difference of \p a and \p b and set \p overflow accordingly.
0123  *
0124  * \param[in] a          The first operand of the subtraction
0125  * \param[in] b          The second operand of the subtraction
0126  * \param[out] overflow  Stores the amount of any overflow
0127  *
0128  * \return The result of the subtraction
0129  */
0130 CELER_FUNCTION RanluxppUInt sub_overflow(
0131     RanluxppUInt a, RanluxppUInt b, unsigned int& overflow)
0132 {
0133     RanluxppUInt sub = a - b;
0134     overflow = (sub > a);
0135     return sub;
0136 }
0137 
0138 //---------------------------------------------------------------------------//
0139 /*!
0140  * Compute difference of \p a and \p b and increment \p carry if there was an
0141  * overflow.
0142  *
0143  * \param[in] a       The first operand of the subtraction
0144  * \param[in] b       The second operand of the subtraction
0145  * \param[out] carry  Maintains sum of all overflows
0146  *
0147  * \return The result of the subtraction
0148  */
0149 CELER_FUNCTION RanluxppUInt sub_carry(
0150     RanluxppUInt a, RanluxppUInt b, unsigned int& carry)
0151 {
0152     unsigned int overflow;
0153     RanluxppUInt sub = sub_overflow(a, b, overflow);
0154 
0155     // Do NOT branch on overflow to avoid jumping code, just add 0 if there was
0156     // no overflow.
0157     carry += overflow;
0158     return sub;
0159 }
0160 
0161 //---------------------------------------------------------------------------//
0162 /*!
0163  * Update r = r - (t1 + t2) + (t3 + t2) * b ** 10.
0164  *
0165  * This function also yields cbar = floor(r / m) as its return value (int64_t
0166  * because the value can be -1). With an initial value of r = t0, this can
0167  * be used for computing the remainder after division by m (see the function
0168  * mod_m in mulmod.h). The function to_ranlux passes r = 0 and uses only the
0169  * return value to obtain the decimal expansion after division by m.
0170  */
0171 CELER_FUNCTION int64_t compute_remainder(Span<RanluxppUInt const, 9> upper,
0172                                          Span<RanluxppUInt, 9> r)
0173 {
0174     // Subtract t1 (24 * 24 = 576 bits)
0175     unsigned int carry = 0;
0176     for (int i : celeritas::range(9))
0177     {
0178         RanluxppUInt r_i = r[i];
0179         r_i = sub_overflow(r_i, carry, carry);
0180 
0181         RanluxppUInt t1_i = upper[i];
0182         r_i = sub_carry(r_i, t1_i, carry);
0183         r[i] = r_i;
0184     }
0185     int64_t c = -(static_cast<int64_t>(carry));
0186 
0187     // Subtract t2 (only 240 bits, so need to extend)
0188     carry = 0;
0189     for (int i : celeritas::range(9))
0190     {
0191         RanluxppUInt r_i = r[i];
0192         r_i = sub_overflow(r_i, carry, carry);
0193 
0194         RanluxppUInt t2_bits = 0;
0195         if (i < 4)
0196         {
0197             t2_bits += upper[i + 5] >> 16;
0198             if (i < 3)
0199             {
0200                 t2_bits += upper[i + 6] << 48;
0201             }
0202         }
0203         r_i = sub_carry(r_i, t2_bits, carry);
0204         r[i] = r_i;
0205     }
0206     c -= carry;
0207 
0208     // r += (t3 + t2) * 2 ** 240
0209     carry = 0;
0210     {
0211         RanluxppUInt r_3 = r[3];
0212         // 16 upper bits
0213         RanluxppUInt t2_bits = (upper[5] >> 16) << 48;
0214         RanluxppUInt t3_bits = (upper[0] << 48);
0215 
0216         r_3 = add_carry(r_3, t2_bits, carry);
0217         r_3 = add_carry(r_3, t3_bits, carry);
0218 
0219         r[3] = r_3;
0220     }
0221     for (int i : celeritas::range(3))
0222     {
0223         RanluxppUInt r_i = r[i + 4];
0224         r_i = add_overflow(r_i, carry, carry);
0225 
0226         RanluxppUInt t2_bits = (upper[5 + i] >> 32) + (upper[6 + i] << 32);
0227         RanluxppUInt t3_bits = (upper[i] >> 16) + (upper[1 + i] << 48);
0228 
0229         r_i = add_carry(r_i, t2_bits, carry);
0230         r_i = add_carry(r_i, t3_bits, carry);
0231 
0232         r[i + 4] = r_i;
0233     }
0234     {
0235         RanluxppUInt r_7 = r[7];
0236         r_7 = add_overflow(r_7, carry, carry);
0237 
0238         RanluxppUInt t2_bits = (upper[8] >> 32);
0239         RanluxppUInt t3_bits = (upper[3] >> 16) + (upper[4] << 48);
0240 
0241         r_7 = add_carry(r_7, t2_bits, carry);
0242         r_7 = add_carry(r_7, t3_bits, carry);
0243 
0244         r[7] = r_7;
0245     }
0246     {
0247         RanluxppUInt r_8 = r[8];
0248         r_8 = add_overflow(r_8, carry, carry);
0249 
0250         RanluxppUInt t3_bits = (upper[4] >> 16) + (upper[5] << 48);
0251 
0252         r_8 = add_carry(r_8, t3_bits, carry);
0253 
0254         r[8] = r_8;
0255     }
0256     c += carry;
0257 
0258     // c = floor(r / 2 ** 576) has been computed along the way via the carry
0259     // flags. Now if c = 0 and the value currently stored in r is greater or
0260     // equal to m, we need cbar = 1 and subtract m, otherwise cbar = c. The
0261     // value currently in r is greater or equal to m, if and only if one of
0262     // the last 240 bits is set and the upper bits are all set.
0263     bool greater_m = r[0] | r[1] | r[2] | (r[3] & 0x0000ffffffffffffull);
0264     greater_m &= (r[3] >> 48) == 0xffff;
0265     for (int i : celeritas::range(4, 9))
0266     {
0267         greater_m &= (r[i] == celeritas::numeric_limits<RanluxppUInt>::max());
0268     }
0269     return c + (c == 0 && greater_m);
0270 }
0271 
0272 //---------------------------------------------------------------------------//
0273 /*!
0274  * Multiply two 576 bit numbers, stored as 9 numbers of 64 bits each.
0275  *
0276  * \param[in]  in1  first factor as 9 numbers of 64 bits each
0277  * \param[in]  in2  second factor as 9 numbers of 64 bits each
0278  *
0279  * \return  result with 18 numbers of 64 bits each
0280  */
0281 CELER_FUNCTION RanluxppArray18 multiply_9x9(RanluxppArray9 const& in1,
0282                                             RanluxppArray9 const& in2)
0283 {
0284     RanluxppArray18 result;
0285 
0286     RanluxppUInt next = 0;
0287     unsigned int nextCarry = 0;
0288 
0289 #if defined(__clang__) || defined(__INTEL_COMPILER) || defined(__CUDA_ARCH__)
0290 #    pragma unroll
0291 #elif defined(__GNUC__) && __GNUC__ >= 8 && !defined(__CUDACC__)
0292 // This pragma was introduced in GCC version 8.
0293 #    pragma GCC unroll 18
0294 #endif
0295     for (int i = 0; i < 18; ++i)
0296     {
0297         RanluxppUInt current = next;
0298         unsigned int carry = nextCarry;
0299 
0300         next = 0;
0301         nextCarry = 0;
0302 
0303 #if defined(__clang__) || defined(__INTEL_COMPILER) || defined(__CUDA_ARCH__)
0304 #    pragma unroll
0305 #elif defined(__GNUC__) && __GNUC__ >= 8 && !defined(__CUDACC__)
0306 // This pragma was introduced in GCC version 8.
0307 #    pragma GCC unroll 9
0308 #endif
0309         for (int j = 0; j < 9; ++j)
0310         {
0311             int k = i - j;
0312             if (k < 0 || k >= 9)
0313             {
0314                 continue;
0315             }
0316             RanluxppUInt fac1 = in1[j];
0317             RanluxppUInt fac2 = in2[k];
0318 #if defined(__CUDA_ARCH__)
0319             // In principle, we could use the "portable" code path with
0320             // __int128 starting from CUDA 11.5, but the math intrinsic is
0321             // equally easy to write and should work in older versions of CUDA.
0322             RanluxppUInt lower = fac1 * fac2;
0323             RanluxppUInt upper = __umul64hi(fac1, fac2);
0324 #elif defined(__SIZEOF_INT128__)
0325 #    ifdef __GNUC__
0326             // This block of code requires 128-bit unsigned integers, which is
0327             // non-standard.  If using GCC, we temporarily disable
0328             // "-Wpedantic".
0329 #        pragma GCC diagnostic push
0330 #        pragma GCC diagnostic ignored "-Wpedantic"
0331             using uint128 = unsigned __int128;
0332 #        pragma GCC diagnostic pop
0333 #    else
0334             using uint128 = unsigned __int128;
0335 #    endif
0336             uint128 prod = fac1;
0337             prod = prod * fac2;
0338 
0339             RanluxppUInt upper = prod >> 64;
0340             RanluxppUInt lower = static_cast<RanluxppUInt>(prod);
0341 #else
0342             RanluxppUInt upper1 = fac1 >> 32;
0343             RanluxppUInt lower1 = static_cast<uint32_t>(fac1);
0344 
0345             RanluxppUInt upper2 = fac2 >> 32;
0346             RanluxppUInt lower2 = static_cast<uint32_t>(fac2);
0347 
0348             // Multiply 32-bit parts, each product has a maximum value of
0349             // (2 ** 32 - 1) ** 2 = 2 ** 64 - 2 * 2 ** 32 + 1.
0350             RanluxppUInt upper = upper1 * upper2;
0351             RanluxppUInt middle1 = upper1 * lower2;
0352             RanluxppUInt middle2 = lower1 * upper2;
0353             RanluxppUInt lower = lower1 * lower2;
0354 
0355             // When adding the two products, the maximum value for middle is
0356             // 2 * 2 ** 64 - 4 * 2 ** 32 + 2, which exceeds a uint64_t.
0357             unsigned int overflow;
0358             RanluxppUInt middle = add_overflow(middle1, middle2, overflow);
0359             // Handling the overflow by a multiplication with 0 or 1 is cheaper
0360             // than branching with an if statement, which the compiler does not
0361             // optimize to this equivalent code. Note that we could do entirely
0362             // without this overflow handling when summing up the intermediate
0363             // products differently as described in the following SO answer:
0364             //    https://stackoverflow.com/a/51587262
0365             // However, this approach takes at least the same amount of
0366             // thinking why a) the code gives the same results without b)
0367             // overflowing due to the mixture of 32 bit arithmetic. Moreover,
0368             // my tests show that the scheme implemented here is actually
0369             // slightly more performant.
0370             RanluxppUInt overflow_add = overflow
0371                                         * (static_cast<RanluxppUInt>(1) << 32);
0372             // This addition can never overflow because the maximum value of
0373             // upper is 2 ** 64 - 2 * 2 ** 32 + 1 (see above). When now adding
0374             // another 2 ** 32, the result is 2 ** 64 - 2 ** 32 + 1 and still
0375             // smaller than the maximum 2 ** 64 - 1 that can be stored in a
0376             // uint64_t.
0377             upper += overflow_add;
0378 
0379             RanluxppUInt middle_upper = middle >> 32;
0380             RanluxppUInt middle_lower = middle << 32;
0381 
0382             lower = add_overflow(lower, middle_lower, overflow);
0383             upper += overflow;
0384 
0385             // This still can't overflow since the maximum of middle_upper is
0386             //  - 2 ** 32 - 4 if there was an overflow for middle above,
0387             //  bringing
0388             //    the maximum value of upper to 2 ** 64 - 2.
0389             //  - otherwise upper still has the initial maximum value given
0390             //  above
0391             //    and the addition of a value smaller than 2 ** 32 brings it to
0392             //    a maximum value of 2 ** 64 - 2 ** 32 + 2.
0393             // (Both cases include the increment to handle the overflow in
0394             // lower.)
0395             //
0396             // All the reasoning makes perfect sense given that the product of
0397             // two 64 bit numbers is smaller than or equal to
0398             //     (2 ** 64 - 1) ** 2 = 2 ** 128 - 2 * 2 ** 64 + 1
0399             // with the upper bits matching the 2 ** 64 - 2 of the first case.
0400             upper += middle_upper;
0401 #endif
0402 
0403             // Add to current, remember carry.
0404             current = add_carry(current, lower, carry);
0405 
0406             // Add to next, remember nextCarry.
0407             next = add_carry(next, upper, nextCarry);
0408         }
0409 
0410         next = add_carry(next, carry, nextCarry);
0411         result[i] = current;
0412     }
0413 
0414     return result;
0415 }
0416 
0417 //---------------------------------------------------------------------------//
0418 /*!
0419  * Compute a value congruent to mul modulo m less than 2 ** 576.
0420  *
0421  * This computes \f$ m = 2^{576} - 2^{240} + 1 \f$. The result in
0422  * \p out is guaranteed to be smaller than the modulus.
0423  *
0424  * \param[in] mul product from multiply_9x9 with 18 numbers of 64 bits each
0425  * \return result with 9 numbers of 64 bits each
0426  */
0427 CELER_FUNCTION RanluxppArray9 compute_modulus(RanluxppArray18 const& mul)
0428 {
0429     RanluxppArray9 result;
0430 
0431     RanluxppArray9 r;
0432     for (auto i : celeritas::range(0, 9))
0433     {
0434         r[i] = mul[i];
0435     }
0436 
0437     // Make a subspan of the last 9 elements of mul
0438     auto mul_end = Span{mul}.subspan<9, 9>();
0439     static_assert(mul_end.size() == 9);
0440 
0441     int64_t c = compute_remainder(mul_end, r);
0442 
0443     // To update r = r - c * m, it suffices to know c * (-2 ** 240 + 1)
0444     // because the 2 ** 576 will cancel out. Also note that c may be zero, but
0445     // the operation is still performed to avoid branching.
0446 
0447     // c * (-2 ** 240 + 1) in 576 bits looks as follows, depending on c:
0448     //  - if c = 0, the number is zero.
0449     //  - if c = 1: bits 576 to 240 are set,
0450     //              bits 239 to 1 are zero, and
0451     //              the last one is set
0452     //  - if c = -1, which corresponds to all bits set (signed int64_t):
0453     //              bits 576 to 240 are zero and the rest is set.
0454     // Note that all bits except the last are exactly complimentary (unless c =
0455     // 0) and the last byte is conveniently represented by c already. Now
0456     // construct the three bit patterns from c, their names correspond to the
0457     // assembly implementation by Alexei Sibidanov.
0458 
0459     // c = 0 -> t0 = 0; c = 1 -> t0 = 0; c = -1 -> all bits set (sign
0460     // extension) (The assembly implementation shifts by 63, which gives the
0461     // same result.)
0462     int64_t t0 = c >> 1;
0463 
0464     // c = 0 -> t2 = 0; c = 1 -> upper 16 bits set; c = -1 -> lower 48 bits set
0465     int64_t t2 = t0 - (c << 48);
0466 
0467     // c = 0 -> t1 = 0; c = 1 -> all bits set; c = -1 -> t1 = 0
0468     // (The assembly implementation shifts by 63, which gives the same result.)
0469     int64_t t1 = t2 >> 48;
0470 
0471     unsigned int carry = 0;
0472     {
0473         RanluxppUInt r_0 = r[0];
0474 
0475         RanluxppUInt out_0 = sub_carry(r_0, c, carry);
0476         result[0] = out_0;
0477     }
0478     for (int i : celeritas::range(1, 3))
0479     {
0480         RanluxppUInt r_i = r[i];
0481         r_i = sub_overflow(r_i, carry, carry);
0482 
0483         RanluxppUInt out_i = sub_carry(r_i, t0, carry);
0484         result[i] = out_i;
0485     }
0486     {
0487         RanluxppUInt r_3 = r[3];
0488         r_3 = sub_overflow(r_3, carry, carry);
0489 
0490         RanluxppUInt out_3 = sub_carry(r_3, t2, carry);
0491         result[3] = out_3;
0492     }
0493     for (int i : celeritas::range(4, 9))
0494     {
0495         RanluxppUInt r_i = r[i];
0496         r_i = sub_overflow(r_i, carry, carry);
0497 
0498         RanluxppUInt out_i = sub_carry(r_i, t1, carry);
0499         result[i] = out_i;
0500     }
0501 
0502     return result;
0503 }
0504 
0505 //---------------------------------------------------------------------------//
0506 /*!
0507  * Compute factor1 * factor2 mod m using local storage.
0508  *
0509  * The result in \p fac_result is guaranteed to be smaller than the modulus.
0510  *
0511  * \param[in] factor1 first factor with 9 numbers of 64 bits each
0512  * \param[in] factor2 second factor with 9 numbers of 64 bits each
0513  */
0514 CELER_FORCEINLINE_FUNCTION RanluxppArray9 compute_mod_multiply(
0515     RanluxppArray9 const& factor1, RanluxppArray9 const& factor2)
0516 {
0517     RanluxppArray18 mul = multiply_9x9(factor1, factor2);
0518     return compute_modulus(mul);
0519 }
0520 
0521 //---------------------------------------------------------------------------//
0522 /*!
0523  * Compute \c base to the \p 2^log_n modulo m.
0524  *
0525  * \param[in]  result base with 9 numbers of 64 bits each
0526  * \param[in]  log_n log_2 of exponent
0527  */
0528 CELER_FUNCTION RanluxppArray9 compute_power_exp_modulus(RanluxppArray9 result,
0529                                                         RanluxppUInt log_n)
0530 {
0531     for (; log_n > 0; --log_n)
0532     {
0533         result = compute_mod_multiply(result, result);
0534     }
0535     return result;
0536 }
0537 
0538 //---------------------------------------------------------------------------//
0539 /*!
0540  * Compute \p base to the \p n modulo m.
0541  *
0542  * The arguments \p base and \p res may point to the same location.
0543  *
0544  * \param[in]  base  with 9 numbers of 64 bits each
0545  * \param[in]  n     exponent
0546  */
0547 CELER_FUNCTION RanluxppArray9 compute_power_modulus(RanluxppArray9 base,
0548                                                     RanluxppUInt n)
0549 {
0550     // Initial state: 1
0551     RanluxppArray9 res = {1, 0, 0, 0, 0, 0, 0, 0, 0};
0552 
0553     while (n)
0554     {
0555         if (n & 1)
0556         {
0557             res = compute_mod_multiply(res, base);
0558         }
0559         n >>= 1;
0560         if (!n)
0561         {
0562             break;
0563         }
0564         base = compute_mod_multiply(base, base);
0565     }
0566 
0567     return res;
0568 }
0569 
0570 //---------------------------------------------------------------------------//
0571 /*!
0572  * Convert RANLUX numbers to an LCG state.
0573  *
0574  * Computes \f$ m = 2^{576} - 2^{240} + 1 \f$.
0575  *
0576  * \param[in] ranlux A struct containing the state and carry numbers
0577  * \return The 576 bits of the LCG state, smaller than m
0578  */
0579 CELER_FUNCTION RanluxppArray9 to_lcg(RanluxppNumber const& ranlux)
0580 {
0581     RanluxppArray9 result;
0582 
0583     RanluxppArray9 const& number = ranlux.number;
0584     unsigned int c = ranlux.carry;
0585 
0586     // Subtract the final 240 bits.
0587     unsigned int carry = 0;
0588     for (int i : celeritas::range(9))
0589     {
0590         RanluxppUInt ranlux_i = number[i];
0591         RanluxppUInt lcg_i = sub_overflow(ranlux_i, carry, carry);
0592 
0593         RanluxppUInt bits = 0;
0594         if (i < 4)
0595         {
0596             bits += number[i + 5] >> 16;
0597             if (i < 3)
0598             {
0599                 bits += number[i + 6] << 48;
0600             }
0601         }
0602         lcg_i = sub_carry(lcg_i, bits, carry);
0603         result[i] = lcg_i;
0604     }
0605 
0606     // Add and propagate the carry bit.
0607     for (RanluxppUInt& lcg_val : result)
0608     {
0609         lcg_val = add_overflow(lcg_val, c, c);
0610     }
0611 
0612     return result;
0613 }
0614 
0615 //---------------------------------------------------------------------------//
0616 /*!
0617  * Convert an LCG state to RANLUX numbers.
0618  *
0619  * \f$ m = 2^{576} - 2^{240} + 1 \f$
0620  *
0621  * \param[in]  lcg     The 576 bits of the LCG state, must be smaller than m
0622  * \result  A struct containing the ranlux numbers (as 576 bits) and the carry
0623  *          bit
0624  */
0625 CELER_FUNCTION RanluxppNumber to_ranlux(RanluxppArray9 const& lcg)
0626 {
0627     RanluxppNumber result;
0628     int64_t c = compute_remainder(lcg, result.number);
0629 
0630     // ranlux = t1 + t2 + c
0631     unsigned int carry = 0;
0632     for (int i : celeritas::range(9))
0633     {
0634         RanluxppUInt in_i = lcg[i];
0635         RanluxppUInt tmp_i = add_overflow(in_i, carry, carry);
0636 
0637         RanluxppUInt bits = 0;
0638         if (i < 4)
0639         {
0640             bits += lcg[i + 5] >> 16;
0641             if (i < 3)
0642             {
0643                 bits += lcg[i + 6] << 48;
0644             }
0645         }
0646         tmp_i = add_carry(tmp_i, bits, carry);
0647         result.number[i] = tmp_i;
0648     }
0649 
0650     // If c = -1, we need to add it to all components.
0651     int64_t c1 = c >> 1;
0652     result.number[0] = add_overflow(result.number[0], c, carry);
0653     for (int i : celeritas::range(1, 9))
0654     {
0655         RanluxppUInt ranlux_i = result.number[i];
0656         add_overflow(ranlux_i, carry, carry);
0657         add_carry(ranlux_i, c1, carry);
0658     }
0659 
0660     result.carry = carry;
0661 
0662     return result;
0663 }
0664 
0665 //---------------------------------------------------------------------------//
0666 }  // namespace detail
0667 }  // namespace celeritas