/* * Copyright 2008-2021 NVIDIA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) # pragma clang system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) # pragma system_header #endif // no system header #include #include #include #include THRUST_NAMESPACE_BEGIN namespace random { template _CCCL_HOST_DEVICE subtract_with_carry_engine::subtract_with_carry_engine(result_type value) { seed(value); } // end subtract_with_carry_engine::subtract_with_carry_engine() template _CCCL_HOST_DEVICE void subtract_with_carry_engine::seed(result_type value) { thrust::random::linear_congruential_engine e( value == 0u ? default_seed : value); // initialize state for (size_t i = 0; i < long_lag; ++i) { m_x[i] = detail::mod(e()); } // end for i m_carry = (m_x[long_lag - 1] == 0); m_k = 0; } // end subtract_with_carry_engine::seed() template _CCCL_HOST_DEVICE typename subtract_with_carry_engine::result_type subtract_with_carry_engine::operator()(void) { // XXX we probably need to cache these m_x[m_k] in a register // maybe we need to cache the use of all member variables int short_index = m_k - short_lag; if (short_index < 0) { short_index += long_lag; } result_type xi; if (m_x[short_index] >= m_x[m_k] + m_carry) { // x(n) >= 0 xi = m_x[short_index] - m_x[m_k] - m_carry; m_carry = 0; } else { // x(n) < 0 xi = modulus - m_x[m_k] - m_carry + m_x[short_index]; m_carry = 1; } m_x[m_k] = xi; ++m_k; if (m_k >= long_lag) { m_k = 0; } return xi; } // end subtract_with_carry_engine::operator()() template _CCCL_HOST_DEVICE void subtract_with_carry_engine::discard(unsigned long long z) { for (; z > 0; --z) { this->operator()(); } // end for } // end subtract_with_carry_engine::discard() template template std::basic_ostream& subtract_with_carry_engine::stream_out(std::basic_ostream& os) const { typedef std::basic_ostream ostream_type; typedef typename ostream_type::ios_base ios_base; const typename ios_base::fmtflags flags = os.flags(); const CharT fill = os.fill(); const CharT space = os.widen(' '); os.flags(ios_base::dec | ios_base::fixed | ios_base::left); os.fill(space); const UIntType long_lag_ = r; for (size_t i = 0; i < r; ++i) { os << m_x[(i + m_k) % long_lag_] << space; } os << m_carry; os.flags(flags); os.fill(fill); return os; } template template std::basic_istream& subtract_with_carry_engine::stream_in(std::basic_istream& is) { typedef std::basic_istream istream_type; typedef typename istream_type::ios_base ios_base; const typename ios_base::fmtflags flags = is.flags(); is.flags(ios_base::dec | ios_base::skipws); for (size_t i = 0; i < r; ++i) { is >> m_x[i]; } is >> m_carry; m_k = 0; is.flags(flags); return is; } template _CCCL_HOST_DEVICE bool subtract_with_carry_engine::equal(const subtract_with_carry_engine& rhs) const { const UIntType long_lag_ = r; bool result = true; for (size_t i = 0; i < r; ++i) { result &= (m_x[(i + m_k) % long_lag_] == rhs.m_x[(i + rhs.m_k) % long_lag_]); } // XXX not sure if this last check is necessary result &= (m_carry == rhs.m_carry); return result; } template std::basic_ostream& operator<<(std::basic_ostream& os, const subtract_with_carry_engine& e) { return thrust::random::detail::random_core_access::stream_out(os, e); } template std::basic_istream& operator>>(std::basic_istream& is, subtract_with_carry_engine& e) { return thrust::random::detail::random_core_access::stream_in(is, e); } template _CCCL_HOST_DEVICE bool operator==(const subtract_with_carry_engine& lhs, const subtract_with_carry_engine& rhs) { return thrust::random::detail::random_core_access::equal(lhs, rhs); } template _CCCL_HOST_DEVICE bool operator!=(const subtract_with_carry_engine& lhs, const subtract_with_carry_engine& rhs) { return !(lhs == rhs); } } // namespace random THRUST_NAMESPACE_END