送分帖,数学功底好的人进

Evap 2011-01-22 02:59:05

现有结构

struct VECTOR3D
{
double x,y,z;
};

代表三维空间中的向量。

问题很简单,
写一个函数生成随机单位向量(随机的,长度为1的向量)
使随机产生的向量在每个方向上的概率均相等.

随机函数只能调用rand()和srand()
...全文
298 44 打赏 收藏 转发到动态 举报
写回复
用AI写文章
44 条回复
切换为时间正序
请发表友善的回复…
发表回复
Evap 2011-01-26
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 superdiablo 的回复:]
你为什么非得把xyz局限在某个范围呢?

引用 26 楼 direct4d 的回复:
引用 25 楼 superdiablo 的回复:
这个为什么肯定不是均匀的?你的理由是什么?

引用 22 楼 direct4d 的回复:
...
有朋友提到,随机X,Y,Z 再单位化,这个方法肯定不是概率均匀的
...


好吧,我这就给你个理由

这样做的话,靠近有8个地方的点要比……
[/Quote]

X,Y,Z总有一个范围啊,就算计算机能够随机出(INF,+INF)按照这个原理,规范化出来的向量也不可能是每个方向都均匀的,道理我已经讲明白了,并且我还专门对这个做了测试的。
tonglei25 2011-01-23
  • 打赏
  • 举报
回复
上面a∈[-pi/2,pi/2],打错了
tonglei25 2011-01-23
  • 打赏
  • 举报
回复
请百度 “三重积分的球坐标变换”

其实就是生成两个随机的角度:a ∈[-pi/2~pi/2]和 b ∈[0,2*pi],a代表向量与x轴的夹角,b代表向量与z轴的夹角

x=r*sin(a)*cos(b);
y=r*sin(a)*cos(b);
z=r*sin(b);

其中r=1



wateryh 2011-01-23
  • 打赏
  • 举报
回复
对LZ的活动时间深表诧异
superdiablo 2011-01-23
  • 打赏
  • 举报
回复
你为什么非得把xyz局限在某个范围呢?
[Quote=引用 26 楼 direct4d 的回复:]
引用 25 楼 superdiablo 的回复:
这个为什么肯定不是均匀的?你的理由是什么?

引用 22 楼 direct4d 的回复:
...
有朋友提到,随机X,Y,Z 再单位化,这个方法肯定不是概率均匀的
...


好吧,我这就给你个理由

这样做的话,靠近有8个地方的点要比其他地方稍微密一些,分别是球的内接正方体的8个顶点附近。

设想有一正方体,长宽高都分为……
[/Quote]
nand库路泽 2011-01-23
  • 打赏
  • 举报
回复
惭愧惭愧!!数学居然都忘了!!
lzl_2008 2011-01-23
  • 打赏
  • 举报
回复
需要两个0到360范围的随机数,分别代表水平方向的角度和竖直方向的角度.可以想像有两个指南针(但针方向是随机的,不指向南),第一个指南针水平摆放,第二个指南针顺着第一个指南针的指针竖直摆放。则第二个指南针的针方向就是楼主需要的向量
Evap 2011-01-23
  • 打赏
  • 举报
回复
我不过也就是最近做了个项目深有体会,
借此帖与大家分享!!
Evap 2011-01-23
  • 打赏
  • 举报
回复
按照刚才的思想还可以做出这样的随机

比如一把武器的攻击力是100~200

但越靠近200概率越小,越靠近100概率越大

则可采用下面代码



// 随机[min,max]实数
inline float RandFloat( float min, float max = 0 )
{
return (rand()/32767)*(max - min) + min;
}

// 随机[min,max]实数,希望靠近min的概率大,靠近max的概率小
inline float RandFloatWishSmall( float min, float max )
{
return (1.0f-sqrt(RandFloat(1)))*(max - min) + min;
}

#include <stdio.h>
void main()
{
float damage;
damage = RandFloatWishSmall(100,200);
printf("%5.1f",damage);
}

Evap 2011-01-23
  • 打赏
  • 举报
回复


// 常数
const float Pi = 3.141592654f;
const float doublePi = 6.28318531f;

// 3D向量
struct VECTOR3D
{
float x,y,z;
};

// 随机[min,max]实数
inline float RandFloat( float min, float max = 0 )
{
return (rand()/32767)*(min - max) + min;
}

// 随机经度
inline float RandLongitude()
{
return RandFloat(doublePi);
}

// 随机纬度
inline float RandLatitude()
{
return asinf(RandFloat(-1, 1));
}

// 随机单位向量
VECTOR3D* RandIdentityVector(VECTOR3D* pOut)
{
if (pOut)
return NULL;

float a = RandLongitude();
float b = RandLatitude();

pOut->x = cosf(a)*cosf(b);
pOut->y = sinf(a)*cosf(b);
pOut->z = sinf(b);
return pOut;
}

Evap 2011-01-23
  • 打赏
  • 举报
回复
是时候结贴了,不然分不够散了.

70分给最接近正确答案的,30分分给用时最少的答案

分布均匀的答案:
生成两个随机的角度:a ∈[0,2*pi],b ∈[-pi/2,pi/2]其中a,b分别代表经度和纬度
a的概率密度曲线为 phi(a) = 1/2*pi ,即每个a等概率密度

关键在于b的分布,b不能像a一样也均匀分布
因为b是纬度,而纬度线长短不一,设想如果b=pi/2的概率密度和b=0的概率密度相等的话, 那么随机出来的向量在南北极将很密集.

怎么随机b的问题转化为:
对于随机变量b ∈[-pi/2,pi/2],
随机出小于b0的概率, 等于球面上小于纬度b0的球面表面积除以总表面积.


球面上小于纬度b0的球面表面积 S(b0) = 2*pi*R*R*(sin(b0)+1).
这个公式怎么得来的这里就不写了吧, 用的知识是微积分.

等于球面上小于纬度b0的球面表面积除以总表面积的比值 P(b0,<) = (sin(b0)+1)/2.

这个公式便是随机出小于纬度b0的概率公式
现在只需求这个P(b0,<)函数的反函数,将概率P∈[0,1]作为均匀分布随机变量代入, 求得b, b必然满足我们要的分布.

最后
x=r*cos(a)*cos(b);
y=r*sin(a)*cos(b);
z=r*sin(b);
schlafenhamster 2011-01-23
  • 打赏
  • 举报
回复
根据“大数定理”任何分布的随机变量和为高斯分布。
抛10000次硬币的分布就是高斯分布
Evap 2011-01-23
  • 打赏
  • 举报
回复
假如你的x,y,z都是-1到1随机,
生成的点就在棱长为2的正方体内均匀分布,对吧

然后在正方体内作一个内切球
落在球内点的是均匀分布的,
但不在球内的点都在什么位置呢? --- 8个顶点附近,
规范化后, 只能使8个顶点附近的点比较密
Evap 2011-01-23
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 superdiablo 的回复:]
这个为什么肯定不是均匀的?你的理由是什么?

引用 22 楼 direct4d 的回复:
...
有朋友提到,随机X,Y,Z 再单位化,这个方法肯定不是概率均匀的
...
[/Quote]

好吧,我这就给你个理由

这样做的话,靠近有8个地方的点要比其他地方稍微密一些,分别是球的内接正方体的8个顶点附近。

设想有一正方体,长宽高都分为n份,然后让在这些网格的交点上都画上点,
我想你应该感觉得出来,正对这正方体的一面的点比较稀少,而你将视线移动至正方体对角线时,是不是感觉点要密一些呢?

既然这样 规范化至单位1后,肯定也是不均匀的。
superdiablo 2011-01-23
  • 打赏
  • 举报
回复
这个为什么肯定不是均匀的?你的理由是什么?
[Quote=引用 22 楼 direct4d 的回复:]
...
有朋友提到,随机X,Y,Z 再单位化,这个方法肯定不是概率均匀的
...[/Quote]
Evap 2011-01-23
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 joanlynnlove 的回复:]
随机生成两个角度a和b。
再根据数学公式可得到x,y,z.
其实都是伪随机的。。。
[/Quote]

[Quote=引用 11 楼 kissxyl 的回复:]
可以这样,预先的创建3个数组
double rx[360],ry[360],rz[360];
给这3个数组赋值为0~359
然后对这3个数组排序,原本判定大小的地方,换用伪随机函数rnd,以此得到3组随机顺序的角度数组。

然后你轮询的使用即可。顺序的使用这3个数组,结果就是随机的。
有了角度,有了向量,你就让3个方向各平均分配一部分,然后随机产生一部分。

思路就这样,代码懒得写……
[/Quote]

这两位朋友的思路都是用角度,正确答案也是用角度
不过这样随机出来的向量在各个方向上不均匀

设想 地球的纬度有南纬90度到北纬90度,
每个纬度有360个经度,
南极90度随到的概率应该和赤道相等
如果南极90度上有100个点,赤道这么大一圈,也只有100个点,那怎么均匀呢?
Evap 2011-01-23
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 tiger9991 的回复:]
楼主,是每个方向上的斜率都相等么?
如果是的话,只要一次使用rand()生成3个参数,以后都是根据向量1来计算即可啊.
如果不是的话,楼主能不能把题目再描述的更清楚些,谢谢
[/Quote]

是每个方向上的概率都相等,注意是三维空间中的

再说详细一点,就是
在半径为1的球体上随意的找一个点。
要求是:
当随机找了很多很多点后,球面上这些点的密度都是均匀的。

可能会有人说不可能绝对均匀,那是当然,因为你抛10000次硬币,不见得就是5000次正面,但至少能保证的是,正面的概率是1/2

Evap 2011-01-23
  • 打赏
  • 举报
回复
貌似真要散分的说,^^

15楼对问题的理解很不错,半径为1的球体上随意的找一个点,要求概率分布是均匀的

有朋友提到,随机X,Y,Z 再单位化,这个方法肯定不是概率均匀的

还有朋友提到概率不可能均匀的问题,所以有一点我必须申明
既然要求了概率均匀,那我们必须先暂且认为rand()函数随机出来的数是均匀等概率的,不然这个问题如何解答呢?
另外rand()函数的值域是0~32767的整数。
tonglei25 2011-01-23
  • 打赏
  • 举报
回复
悲剧,太粗心了,谢谢楼上提醒。再次更正 x=r*sin(a)*cos(b);y=r*sin(a)sin(b);z=r*cos(a);
peng_weida 2011-01-23
  • 打赏
  • 举报
回复
楼上的公式 貌似 不正确呀
加载更多回复(20)

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧