上周有个做前端的 A 同学把一段旋转动画的参数甩给我,说“明明只转了 45 度,方块为什么歪成这样”。我看了一眼他的代码,顺手让他搜一下 cos45度等于多少,结果他回我一串关键词:cosin等于多少_cos45度等于多少。这个搜索串其实特别典型——一半是拼写手滑(cosin 是 cosine 的常见错拼),一半是真正的疑问:cos45° 到底等于几,这个数是怎么来的,我该保留几位小数。先给结论:cos45° = √2/2 = 1/√2 ≈0.7071067811865476,cosin 不是一个新函数,它就是 cosine(余弦)被敲快了的结果。这个看起来只有初中难度的问题,实际在图形开发、嵌入式、数据分析、结构放样里天天被翻出来,翻车率还相当高——有人把角度和弧度搞混算出 0.5253,有人把小数值截成 0.7 导致装配偏了几毫米。这篇就把这个搜索词彻底拆干净:值和推导、精度怎么取、代码里怎么写、算错了怎么查,不管你是刚学三角函数的,还是十年没碰数学突然要在项目里用一下的,都能直接抄走。
1. 先把问题拆开:cosin 是什么,cos45° 又是什么
1.1 “cosin” 不是新函数,是 cosine 的手滑写法
搜索词里出现 cosin 的频率高得惊人,我第一次看到还以为是什么冷门记号。查下来发现它基本就是 cos + sin 两个词在键盘上打架的产物,或者是英文 cosine 拼漏了最后一个 e。在数学里没有叫 cosin 的独立函数,正规写法只有三种:cos(缩写)、cosine(全称)、cos θ(带自变量)。
真正容易混的是 cos 和 sin 本身,而不是拼写。你要记住的只有一句话:cos 管的是“挨着角的边”,sin 管的是“对着角的边”,两者都除以斜边。中文里“余弦”的“余”字其实就在暗示它是“剩下的那条边”——你对着角看,对着的那条是正弦的,剩下挨着的那条就是余弦的。
这个区分在写代码时尤其要命。我做图形项目时见过不少把旋转矩阵里 sin 和 cos 位置写反的案例,表现是图形旋转方向拧了、或者运动轨迹变成椭圆。矩阵里第一行第一列是 cos,第一行第二列是 -sin,这个位置关系是死的,记错一个符号,整个坐标系就跟着错。所以当你搜“cosin 等于多少”的时候,先把提问对象确认清楚:你要的是余弦,不是正弦,也不是正切。这三个在 45° 这个特殊角上恰好有两个值撞在一起,更容易掩盖错误——sin45° 和 cos45° 都是 0.7071,你写错了也看不出来,直到换到 30° 或 60° 才暴雷。
1.2 cos45° 的准确值:√2/2,以及它的三种等价写法
cos45° 的精确值是 √2/2,做一个简单除法:√2 ≈ 1.41421356237,除以 2 得0.7071067811865476。它还有几个完全等价的写法,不同场合用不同形式,别被它们绕晕:
| 写法 | 数值 | 常见使用场合 |
|---|---|---|
| √2/2 | 0.70710678… | 教科书答案、公式推导、手算 |
| 1/√2 | 0.70710678… | 电学、信号处理、归一化系数 |
| 0.7071 | 0.7071 | 工程图纸、快速估算 |
| 0.70710678 | 0.70710678 | 一般编程常量 |
| sin(π/4) | 0.70710678… | 代码里最常见的实际调用形式 |
为什么会有两种写法?因为 √2/2 是把分母有理化之后的结果,1/√2 是没有理化的原始形态。数值上它们一模一样,只是 1/√2 在推导时更自然——比如单位正方形对角线的长度是 √2,把它投影到坐标轴上,每一段就是 1/√2 乘以斜边长度。
顺便把 45° 附近几个常用角的值列全,这几个数在项目里出现的概率加起来能占到九成,值得直接记住:
| 角度 | 弧度 | sin | cos | tan |
|---|---|---|---|---|
| 0° | 0 | 0 | 1 | 0 |
| 30° | π/6 ≈ 0.5236 | 0.5 | √3/2 ≈ 0.8660 | √3/3 ≈ 0.5774 |
| 45° | π/4 ≈ 0.7854 | √2/2 ≈ 0.7071 | √2/2 ≈ 0.7071 | 1 |
| 60° | π/3 ≈ 1.0472 | √3/2 ≈ 0.8660 | 0.5 | √3 ≈ 1.7321 |
| 90° | π/2 ≈ 1.5708 | 1 | 0 | 无穷 |
注意 45° 那一行,sin 和 cos 完全相等,tan 恰好等于 1。这三个“整”是 45° 独有的性质,也是它在工程上被大量使用的原因:斜率和投影长度在 45° 时相等,算起来最省事。比如做倒角,C1 的 45° 倒角两个方向切掉的量一样;做坡度,45° 坡对应的坡度比正好是 1:1。
2. 为什么偏偏是 √2/2:三条推导路线,最后都落到同一个数
2.1 走几何:等腰直角三角形里邻边比斜边
最直观的路子是从直角三角形出发。余弦的定义是“角的邻边长度除以斜边长度”。45° 意味着这个直角三角形还有一个角是 45°(因为三个角加起来 180°,直角占 90°),两个锐角相等,那么它们对的边也相等,这就是一个等腰直角三角形。
设两条直角边长度都是 1。根据勾股定理,斜边 = √(1² + 1²) = √2。取其中一个 45° 角,它的邻边就是长度为 1 的那条直角边,于是 cos45° = 邻边 / 斜边 = 1 / √2。分子分母同乘 √2,得到 √2/2。
这条推导最关键的一步是“设直角边为 1”。这一步之所以能随便设,是因为三角函数只看比例,不看绝对大小——你把三角形放大十倍,边长都变成 10 和 10√2,比值还是 1/√2。这就是为什么三角函数能用来描述角度而不受尺寸影响,也是它在图纸缩放、地图投影、屏幕适配里通用的根本原因。
注意:初学者最常见的错误是把邻边和斜边认反,尤其是在图上角画在右边的时候。判断方法是:从这个角出发,沿着两条边往外走,不是斜的那条就是邻边,斜对着直角的那条永远是斜边。
2.2 走单位圆:把“比”变成“坐标”
直角三角形只适用于 0° 到 90°,一旦角度超过 90° 或者变成负数,定义就撑不住了。工程上更通用的是单位圆定义:在坐标平面上画一个半径为 1 的圆,从原点出发沿逆时针方向转 θ 角,与圆交于一点 P,那么P 的横坐标就是 cos θ,纵坐标就是 sin θ。
45° 的时候,点 P 的横纵坐标相等(因为 45° 这条射线就是 y = x),同时又落在单位圆上,所以 x² + y² = 1。代入 x = y,得 2x² = 1,x = 1/√2 = √2/2。到这里和几何推导完全一致,但它顺手解决了直角三角形解决不了的问题:cos120° = -0.5 这种负值怎么来的?看横坐标在左侧就是负的,一目了然。
单位圆这套定义在代码里对应得很直接。做图形旋转的时候,一个点绕原点转 θ 度,新坐标就是 (x·cosθ - y·sinθ, x·sinθ + y·cosθ),本质就是把点的极坐标角度加上 θ。我调试旋转逻辑的时候有个很省事的自检手段:拿点 (1, 0) 转 45°,结果应该是 (0.7071, 0.7071),长度仍然是 1。如果算出来长度不是 1,那肯定是矩阵写错了或者把 sin/cos 用反了。
2.3 走级数:计算器内部其实在算多项式
前面两条路告诉你“答案是什么”,但计算器按一下就出 0.7071067811865476,它是怎么算的?答案是泰勒级数。余弦的展开式是:
cos x = 1 - x²/2! + x⁴/4! - x⁶/6! + x⁸/8! - …
这里的 x 必须是弧度。45° 换成弧度是 π/4 ≈ 0.7853981634。我实际算了一遍,看每一轮加进去之后的结果:
| 累加到第几项 | 计算结果 | 与真值 0.7071067812 的差值 |
|---|---|---|
| 1 - x²/2! | 0.6915749 | 1.55 × 10⁻² |
| + x⁴/4! | 0.7074292 | 3.2 × 10⁻⁴ |
| - x⁶/6! | 0.7071032 | 3.6 × 10⁻⁶ |
| + x⁸/8! | 0.7071068 | 约 5 × 10⁻⁸ |
可以看到收敛得非常快,算到 8 次方这一项时,7 位有效数字已经全部正确。这也是为什么很多嵌入式库压根不存三角函数表,直接用四五项泰勒展开就够了——运算量比查表加插值还小。
这条路线还有个副产品:它解释了为什么角度一旦超过一定范围,直接用级数会精度崩掉。x 越大,x 的高次幂增长越快,需要更多项才能收敛。所以正规实现都会先把角度规约到 [-π/4, π/4] 区间内再展开,这一步叫“参数规约”,是很多数值库出 bug 的重灾区。你自己手写实现的话,别省这一步。
3. 从 0.7071 到工程可用:精度、单位、有效数字
3.1 保留几位才够:按场景选精度
我见过两种极端:一种是全篇写 0.7071 就完事,结果做精密装配时累积误差肉眼可见;另一种是把 0.7071067811865476 一路抄下去,代码里一串 16 位小数,可读性极差还没意义。到底保留几位,取决于你拿它干什么:
| 使用场景 | 建议精度 | 理由 |
|---|---|---|
| 口算、估量、草图 | 0.7 | 误差 1%,对整体判断无影响 |
| 手算题目、课堂作业 | √2/2 或 0.7071 | 保留 4 位足够,写精确值更好 |
| 一般业务代码 | 0.70710678 | 双精度下 8 位有效数字够用 |
| 图形渲染、游戏 | 用库函数直接算 | 不要手写常量 |
| 精密测量、结构放样 | 保留到实际有效位数 | 取决于测量工具本身的精度 |
| 嵌入式定点数 | Q15 下取 23170 | 见后文定点数一节 |
举个具体的量级感:如果一个 100 毫米的零件,用 0.7071 代替 0.70710678,单次误差约 0.0000068 毫米,也就是 6.8 纳米,完全不用管。但如果这个系数要在一个循环里累积一万次,误差可能放大到 0.068 毫米,那就得看你的公差了。
还有一点值得说:不要自己手写 0.70710678 这种常量去替代库函数,除非你有明确理由。库函数的实现经过了极端值、大角度、负角度的完整测试,你自己写的常量只覆盖了 45° 这一个点,一旦输入不是 45° 就抓瞎。手写常量只在一种场景下合理:你知道角度永远是 45°,且不想引入额外的计算开销。
3.2 度与弧度:90% 的“算出来不对”都出在这
这是我在实际项目里见得最多的坑,没有之一。你写cos(45),很多语言会返回0.5253219888177297,而不是 0.7071。为什么?因为编程语言里的三角函数默认吃弧度,45 弧度不是 45 度。
45 弧度到底是多少度?45 ÷ (2π) ≈ 7.162 圈,也就是转了 7 整圈再转过 0.162 圈,换算成弧度就是 45 - 7×2π ≈ 1.0177 弧度,约等于 58.3°。cos58.3° ≈ 0.5253,和计算结果完全对得上。这个换算过程建议你自己手算一遍,比背十遍“要用弧度”管用。
正确的写法是先把角度换成弧度:45 × π / 180 = π/4 ≈ 0.7853981634,再传给函数。Excel 里对应的是COS(RADIANS(45)),直接写COS(45)同样是 0.5253。计算器就更隐蔽了,屏幕上有个小小的 DEG / RAD 标记,切错了算出来就是这个数,很多人以为是计算器坏了。
记住一句口诀:微积分和编程默认弧度,图纸和日常对话默认角度。跨过这条线就要显式换算,不要指望任何默认值。
顺带说个反向的坑:有些老代码里存的是“度 × 100”这种整数表示(比如 4500 代表 45°),换算时要先除以 100 再转弧度,漏掉一步就是几千倍的误差。
3.3 特殊角的记忆法(不用死背表)
很多人记不住 30°、45°、60° 的值,其实没必要硬背。正弦那一行,按 0°、30°、45°、60°、90° 的顺序,分子依次是 √0、√1、√2、√3、√4,统一除以 2 就是答案:0、0.5、0.7071、0.8660、1。余弦就是把这一行倒过来读:1、0.8660、0.7071、0.5、0。正切是 sin 除以 cos,45° 时两者相等,所以是 1。
这个规律的妙处在于它是“长”出来的,不是“背”出来的。你只要记住“分子开根号、分母是 2”这一条,五行数据就全在手上。真忘了也不要紧,45° 直接回到等腰直角三角形现场推,两分钟的事,比翻表快。
另一个我常用的记忆锚点:0.7071 这个数在工程里到处都能碰到。它是正方形对角线和边长的比值的倒数、是半功率点(-3dB)对应的归一化系数、是很多滤波器系数的标准值。你在不同领域反复看到同一个数字,自然就记住了。
4. 代码与工程现场:cos45° 真正被用在哪里
4.1 三种常见语言里的调用与坑
写代码算余弦,语法差不多,坑却各不相同。我整理了常用的几种:
import math # 正确:先转弧度 print(math.cos(math.pi / 4)) # 0.7071067811865476 print(math.cos(math.radians(45))) # 0.7071067811865476 # 错误:直接传角度 print(math.cos(45)) # 0.5253219888177297 # 常量和库函数混用时的写法 COS_45 = math.sqrt(2) / 2 # 0.7071067811865476// JS 同样只吃弧度 console.log(Math.cos(Math.PI / 4)); // 0.7071067811865476 console.log(Math.cos(45)); // 0.5253219888177297 console.log(Math.cos(45 * Math.PI / 180)); // 0.7071067811865476#include <math.h> #include <stdio.h> int main(void) { double a = cos(M_PI / 4); /* 0.7071067811865476 */ double b = cos(45.0 * M_PI / 180); /* 0.7071067811865476 */ double c = cos(45.0); /* 0.5253219888177297 */ printf("%.16f\n%.16f\n%.16f\n", a, b, c); return 0; }C 这边要注意两件事:一是编译时通常要加-lm链接数学库,否则会报未定义引用;二是M_PI严格来说不是标准 C 的一部分,某些编译器要开_USE_MATH_DEFINES或者在 C99 以上的特定配置下才可见。稳妥的写法是自己定义#define PI 3.14159265358979323846,省得换平台就编译不过。
还有一个隐蔽的差异:不同语言返回的末位可能不完全一样。Python 和 JS 在 45° 上都返回 0.7071067811865476,但某些平台的实现可能返回 …4758。这不是 bug,是浮点数本身的表示限制,正常比较时不要用==,用差值小于 1e-9 判断。
4.2 图形旋转、向量夹角与相似度计算
45° 这个角在图形里出现的频率极高,因为它是“斜着放”的最自然选择,而且旋转矩阵的四个元素里有三个幅值相等,调试时容易对照。一个点 (x, y) 绕原点逆时针转 θ 后的坐标是:
import math def rotate(x, y, deg): t = math.radians(deg) c, s = math.cos(t), math.sin(t) return x * c - y * s, x * s + y * c print(rotate(1, 0, 45)) # (0.7071067811865476, 0.7071067811865475)拿 (1, 0) 验证:转 45° 之后横纵坐标相等,都约等于 0.7071,长度平方 = 0.5 + 0.5 = 1,没变形。这个自检我每次写旋转都要跑一遍,能挡掉一大半低级错误。
向量夹角是另一个高频场景。两个向量的余弦相似度就是 cos θ = (a·b) / (|a|·|b|)。夹角 45° 时这个值是 0.7071,意味着两个方向“比较像但不完全一样”。做文本相似度、推荐召回、特征匹配时,0.7 上下通常是个分水岭——低于 0.7 就认为相关性不够。这个阈值不是随便定的,它恰好对应 45° 的方向偏差,超过 45° 就说明两个向量在半数以上的维度上已经走偏了。
还有个容易忽略的点:45° 旋转在图像处理里是最难插值好的角度之一。90° 的整数倍旋转只是像素搬运,没有精度损失;45° 之后每个目标像素都落在四个原像素之间,必须做双线性或双三次插值,边缘会明显变软。我处理扫描件的时候宁可先转 90° 再微调 ±5°,把 45° 这种大角度旋转放到最后一步做,就是为了少一次重采样。
4.3 嵌入式与定点数:23170 这个数字的来历
在单片机、电机控制这类没有浮点单元或者浮点太慢的场景,cos45° 会被存成定点数。最常用的是 Q15 格式,把 [-1, 1] 映射到 [-32768, 32767] 的整数区间:
- 0.70710678 × 32768 = 23170.475
- 四舍五入取23170
- 反算回浮点:23170 / 32768 = 0.707092285,误差约 1.45 × 10⁻⁵
如果你翻过电机矢量控制(FOC)的源码,会频繁看到 23170 这个常数,它就是 √2/2 的 Q15 表示。同样常见的是 16384(0.5)、28378(√3/2 ≈ 0.866)这些。这类实现通常还会配一张 0 到 90° 的正弦表,按 256 或 1024 个点等分,查表加线性插值,比调用浮点库快一个数量级。
用定点数有几个必须注意的地方,我踩过:
- 乘法之后要右移 15 位还原,忘记移位是最常见的错,结果会大 32768 倍。
- 两个 Q15 数相乘,中间结果会超出 32 位,要用 int64 或者拆成高低位算,直接乘会溢出变负数。
- 负数的舍入方向要统一,
>>对负数是向下取整,跟+ 0.5再取整的结果不一致,混用会导致 ±1 的抖动。
提醒:定点数的误差是累积的。单次 1.45 × 10⁻⁵ 看着无所谓,但如果它在积分环节里被累加几千次,就可能变成肉眼可见的漂移。做闭环控制时我一般会定期把积分项拉回浮点重新校准一次。
5. 排查实录:结果不对时按这张表逐条对
5.1 六类高频错误与定位方法
算余弦算错,八成跑不出下面六种情况。我把它整理成一张速查表,出问题的时候按顺序过一遍,基本能定位到:
| 现象 | 最可能原因 | 快速验证方法 |
|---|---|---|
| 得到 0.5253 左右 | 传了角度没转弧度 | 输入改成 0.7854 再试一次 |
| 得到 0.8660 | 把 cos 写成了 sin 但不自知 | 换 30° 试,cos30 应是 0.866,若得 0.5 则 sin/cos 反了 |
| 得到 -0.7071 | 角度放错了象限 | 检查是 +45 还是 +135、225 |
| 得到 0.707 但符号/方向错 | 旋转矩阵里 -sin 的位置写反 | 拿 (1,0) 转 90° 看是否得 (0,1) |
| 图形尺寸越转越大或越小 | 忘了归一化,或半径没乘对 | 算旋转后向量长度是否为 1 |
| 定点数结果大得离谱 | 乘法后没右移 | 结果除以 32768 看是否合理 |
这张表里我最想强调的是第二行。sin 和 cos 在 45° 上相等,所以拿 45° 做测试根本区分不出来你写没写反,必须换到 30° 或 60° 才能暴露。做单元测试的时候,45° 只能验证“数值对不对”,验证不了“函数选对没选对”,这两个断言得分开写。
还有个更隐蔽的:某些老的计算库角度是顺时针为正,或者 0° 指向不是正右方而是正上方。这类差异在 45° 上表现为结果符号不同,很容易被当成程序 bug 查半天。接手新库的时候,我第一件事就是画个 0°、90°、180° 的基准点验证坐标系,比读文档快。
5.2 我自己踩过的三个坑
第一个坑是单位混用。有个批处理脚本里,角度从配置文件读进来是度,我图省事直接丢给 Math.cos,跑了三个月没人发现,因为那个角度恰好一直是 0(cos0 = 1,两种单位下都是 1)。直到有人配了个非零角度,整个结果全歪。教训是:函数入口处就把单位写进参数名里,比如angleDeg、angleRad,比写注释管用得多。
第二个坑是常量精度。早期为了省事,我在一个坐标转换里写了0.71,单次看没问题。后来这个转换在一次渲染里被调用了四十多次(逐层嵌套),误差滚到肉眼可辨的偏移,查了两天才发现根源是一个两位小数。从那以后我的规矩是:只要这个数会参与多次运算,就用库函数或者至少八位有效数字。
第三个坑是边界值。cos 在 90° 附近对输入极其敏感,角度差 0.01° 结果就变了 0.00017。我在做姿态解算时,一度以为陀螺仪在漂,最后发现是角度输入只保留了 2 位小数,量化误差被 cos 的陡峭段放大了。处理办法是那个区间改用 sin 计算再转换,避开敏感区。
说到底,cos45度等于多少 这个问题本身一点都不难,难的是搞清楚“我现在到底在哪个单位制里、需要几位精度、这个数是拿来做判断还是做累加”。这三件事想清楚了,0.7071 这个数才能真正为你所用,而不是变成下一个 bug 的来源。我自己现在的习惯是,看到任何三角函数相关的代码,先花十秒找单位换算那一行——找到了再往下读,找不到就先补上。