LeetCode圆内随机点生成问题排查:结果精度异常原因?
圆内随机点生成精度异常排查
问题描述
在完成LeetCode圆内随机点生成题目时,编写了如下C++代码:
class Solution { private: double c_radius; double xcenter; double ycenter; public: Solution(double radius, double x_center, double y_center) { c_radius = radius; xcenter = x_center; ycenter = y_center; } vector<double> randPoint() { double randomradius= (sqrt((double)rand()) / RAND_MAX) * c_radius; double randomangle= ((double)rand() / RAND_MAX) * 360.0; double yp= sin(randomangle)*randomradius; double xp= cos(randomangle)*randomradius; std::vector<double> point= {xp+xcenter, yp+ycenter}; return point; } };
当测试输入为[[0.01,-73839.1,-3289891.3]]时,生成的点始终是类似[-73839.10000,-3289891.30000]的固定精度值,无法得到预期的带更多小数位的随机点(如[-73839.10006,-3289891.30228]),请求排查问题是否出在数学逻辑上。
问题分析与解决
1. 核心问题:三角函数的角度单位错误
C++标准库中的sin()和cos()函数要求输入参数为弧度值,但当前代码中生成的randomangle是0~360的角度值,直接传入会导致计算严重偏差:
- 当角度值很小时(比如0.1度),对应的弧度值约为0.001745,而直接传入0.1作为弧度的话,
sin(0.1)≈0.0998,cos(0.1)≈0.995,两者差距极大。 - 对于测试用例中的极小半径(0.01),错误的角度计算会导致偏移量
xp、yp极小,加上中心坐标的大数后,小数部分被精度截断,最终显示为固定值。
2. 修正方案
将角度转换为弧度值,直接生成0~2π范围内的随机弧度即可:
#include <cmath> // 需包含此头文件以使用sin、cos和M_PI class Solution { private: double c_radius; double xcenter; double ycenter; public: Solution(double radius, double x_center, double y_center) { c_radius = radius; xcenter = x_center; ycenter = y_center; } vector<double> randPoint() { // 保持半径的均匀分布逻辑(sqrt是正确的,避免点集中在圆心) double r = sqrt(static_cast<double>(rand()) / RAND_MAX) * c_radius; // 生成0到2π的随机弧度 double theta = static_cast<double>(rand()) / RAND_MAX * 2 * M_PI; double xp = cos(theta) * r; double yp = sin(theta) * r; return {xp + xcenter, yp + ycenter}; } };
3. 额外优化建议
- 如果编译器不支持
M_PI,可以手动定义:#define M_PI 3.14159265358979323846 rand()的精度有限(通常是15位范围),对于极小半径场景,可改用C++11的<random>库提升随机数精度,示例:
#include <random> class Solution { private: double c_radius; double xcenter; double ycenter; std::mt19937 gen; std::uniform_real_distribution<double> dist; public: Solution(double radius, double x_center, double y_center) : c_radius(radius), xcenter(x_center), ycenter(y_center), gen(std::random_device{}()), dist(0.0, 1.0) {} vector<double> randPoint() { double r = sqrt(dist(gen)) * c_radius; double theta = dist(gen) * 2 * M_PI; double xp = cos(theta) * r; double yp = sin(theta) * r; return {xp + xcenter, yp + ycenter}; } };
内容的提问来源于stack exchange,提问作者MP3D
相关产品推荐
相关产品推荐

