10705
题目
[2.2] 输入维数 n,再输入两个 n 维向量在某直角坐标系内的坐标,输出它们的夹角。
解析
令
其中:
弧度转角度:除以 180,再乘以圆周率。
答案
c
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
// 判断是否为零向量
int is_zero_vector(const double* v, int n) {
for (int i = 0; i < n; i++) {
if (fabs(v[i]) > 1e-10) return 0; // 使用小阈值判断是否为 0
}
return 1;
}
double dot_product(const double* a, const double* b, int n) {
double sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i] * b[i];
}
return sum;
}
double vector_length(const double* v, int n) {
return sqrt(dot_product(v, v, n));
}
int main(void) {
int n;
printf("请输入向量维数:");
scanf("%d", &n);
if (n <= 0) {
printf("错误:维数必须为正整数\n");
return 1;
}
double* v1 = malloc(n * sizeof(double));
double* v2 = malloc(n * sizeof(double));
if (!v1 || !v2) {
printf("错误:内存分配失败\n");
free(v1);
free(v2);
return 1;
}
printf("请输入第一个向量的坐标:\n");
for (int i = 0; i < n; i++) {
scanf("%lf", &v1[i]);
}
printf("请输入第二个向量的坐标:\n");
for (int i = 0; i < n; i++) {
scanf("%lf", &v2[i]);
}
// 检查零向量
if (is_zero_vector(v1, n) || is_zero_vector(v2, n)) {
printf("错误:零向量没有方向,无法计算夹角\n");
free(v1);
free(v2);
return 1;
}
double cos_theta = dot_product(v1, v2, n) /
(vector_length(v1, n) * vector_length(v2, n));
// 处理数值误差导致的 cos_theta > 1 或 cos_theta < -1 的情况
if (cos_theta > 1) cos_theta = 1;
if (cos_theta < -1) cos_theta = -1;
double angle = acos(cos_theta) * 180.0 / M_PI;
printf("两向量的夹角为:%.2f 度\n", angle);
free(v1);
free(v2);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
测试数据
点击展开
txt
# 测试点 1
输入:
2
1 0
0 1
输出:
90.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 2
输入:
3
1 1 1
1 1 1
输出:
0.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 3
输入:
4
1 0 0 0
-1 0 0 0
输出:
180.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 4
输入:
5
1 1 1 1 1
1 0 0 0 -1
输出:
90.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 5
输入:
10
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
输出:
14.42
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 6
输入:
20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1
输出:
90.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 7
输入:
50
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
输出:
90.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 8
输入:
100
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
输出:
180.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 9
输入:
3
0.5 0.5 0.7071067811865476
0.5 0.5 -0.7071067811865476
输出:
90.00
1
2
3
4
5
6
7
2
3
4
5
6
7
txt
# 测试点 10
输入:
4
0.5773502691896258 0.5773502691896258 0.5773502691896258 0
0.5 0.5 0.5 0.5
输出:
19.47
1
2
3
4
5
6
7
2
3
4
5
6
7
题外话
在高维空间中,随机选择两个向量时,这两个向量垂直或接近垂直的概率会随着维数的增加而增大。
数学证明
考虑在 n 维空间中随机选择两个单位向量
根据大数定律,当 n 趋于无穷时,这个点积会趋近于 0(因为每一项
设
,则 (因为 和 独立且对称分布) (因为是单位向量)根据中心极限定理,当
时:因此:
当
这说明在高维空间中,随机选择的两个向量很可能接近垂直(夹角接近 90°)。
直观理解
可以这样理解:在高维空间中,向量的分量越多,它们的点积中的正项和负项相互抵消的机会就越大,使得最终的点积趋近于零,即夹角趋近于 90°。