// Copyright (c) 2020-2025 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include #include #include #include #include #include #include "include/host_device.h" // The technique demonstrated in the example monte_carlo.cu // assigns an independently seeded random number generator to each // of 30K threads, and uses a hashing scheme based on thread index to // seed each RNG. This technique, while simple, may be succeptible // to correlation among the streams of numbers generated by each RNG // because there is no guarantee that the streams are not disjoint. // This example demonstrates a slightly more sophisticated technique // which ensures that the subsequences generated in each thread are // disjoint. To achieve this, we use a single common stream // of random numbers, but partition it among threads to ensure no overlap // of substreams. The substreams are generated procedurally using // default_random_engine's discard(n) member function, which skips // past n states of the RNG. This function is accelerated and executes // in O(lg n) time. struct estimate_pi { __host__ __device__ float operator()(unsigned int thread_id) { float sum = 0; unsigned int N = 5000; // samples per stream // note that M * N <= default_random_engine::max, // which is also the period of this particular RNG // this ensures the substreams are disjoint // create a random number generator // note that each thread uses an RNG with the same seed thrust::default_random_engine rng; // jump past the numbers used by the subsequences before me rng.discard(N * thread_id); // create a mapping from random numbers to [0,1) thrust::uniform_real_distribution u01(0, 1); // take N samples in a quarter circle for (unsigned int i = 0; i < N; ++i) { // draw a sample from the unit square float x = u01(rng); float y = u01(rng); // measure distance from the origin float dist = sqrtf(x * x + y * y); // add 1.0f if (u0,u1) is inside the quarter circle if (dist <= 1.0f) { sum += 1.0f; } } // multiply by 4 to get the area of the whole circle sum *= 4.0f; // divide by N return sum / N; } }; int main(void) { // use 30K subsequences of random numbers int M = 30000; float estimate = thrust::transform_reduce( thrust::counting_iterator(0), thrust::counting_iterator(M), estimate_pi(), 0.0f, thrust::plus()); estimate /= M; std::cout << "pi is around " << estimate << std::endl; return 0; }