<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://abbywitmia.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://abbywitmia.github.io/" rel="alternate" type="text/html" /><updated>2021-11-24T14:50:02+08:00</updated><id>https://abbywitmia.github.io/feed.xml</id><title type="html">ΓΝΩΘΙ ΣΑΥΤΟΝ</title><subtitle>Wit的个人博客</subtitle><author><name>Wit</name></author><entry><title type="html">通过夫妻分居政策拿到北京户口</title><link href="https://abbywitmia.github.io/2021/11/24/beijing-hukou/" rel="alternate" type="text/html" title="通过夫妻分居政策拿到北京户口" /><published>2021-11-24T00:00:00+08:00</published><updated>2021-11-24T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/11/24/beijing-hukou</id><content type="html" xml:base="https://abbywitmia.github.io/2021/11/24/beijing-hukou/">&lt;h1 id=&quot;背景&quot;&gt;背景&lt;/h1&gt;
&lt;p&gt;一些政府部门,企事业单位有政策,可以通过夫妻分居事由,解决户口问题.&lt;br /&gt;
下面说说具体步骤.&lt;/p&gt;

&lt;h2 id=&quot;action1北京政务服务中心&quot;&gt;action1:北京政务服务中心&lt;/h2&gt;
&lt;p&gt;先去&lt;a href=&quot;https://zwfw.gaj.beijing.gov.cn/rkgl/&quot;&gt;北京市公安局&lt;/a&gt;,选择第16项&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;因工作原因调动办理户口准迁手续&lt;/code&gt;,你会看到一个身份证输入框.&lt;/p&gt;

&lt;p&gt;如果你的case已经被人社部批准,输入身份证号,点击下一步,会得到提示信息.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;办理人社部批准的干部、工人调动及随迁家属、夫妻分居户口准迁手续

办理机构：北京市公安局户政服务窗口
办理地址：北京市丰台区西三环南路1号（北京市政务服务中心）三层B区
办理时间：工作日上午9:00-12：00，下午13：30-17：00
办理时限：手续齐全即时办理
申请条件：证件材料齐全、准迁数据准确
办理流程：直接持落户批件及相关证件材料在北京市公安局户政服务窗口办理
联系电话：010-89150418
证件材料：
1、人社部批件（原件1份，纸质）；
2、进京落户人员的居民户口簿（常住人口登记卡或户籍证明）（原件1份，纸质）；
3、进京落户人员的居民身份证（落户批件上所涉及成年人提供。原件1份，纸质）；
4、进京落户地址情况。如落集体户口的提供集体户单位同意落户情况（原件1份，纸质）；如迁入在京直系亲属户内须提供直系亲属的居民户口簿（原件1份，纸质）、房产证（原件1份，纸质）及亲属关系证件材料（原件1份，纸质）；如新立户的提供本人或直系亲属的房产证（原件1份，纸质）及亲属关系证件材料（原件1份，纸质）。

收费标准：不收费
办理依据：
公安部人事部劳动部《关于干部、工人调动办理户口迁移手续有关问题的通知》(公通字〔1994〕97号)“县、市以上(包括县、市)人事、劳动部门按照干部、工人的管理权限在批准干部、工人调动工作，录用干部、招收工人，办理离退休干部异地安置和博士后研究人员及其期满后分配工作时的随迁家属等工作时，如需办理户口迁移手续，应将人事、劳动部门的批准通知及调动人员情况登记表抄送迁入地县级以上(含县级)公安机关，公安机关凭上述材料并根据公安部有关户籍管理的规定签发户口准迁证，供调动工作的干部、职工及随迁家属办理户口迁移手续时使用”；公安部《关于启用新的户口迁移证、户口准迁证的通知》(公通字〔1994〕62号)“ 户口准迁证的使用范围是：凡跨市(系指市区，下同)、县范围的户口迁移”；北京市公安局《关于启用新的户口迁移证、户口准迁证的通知》(京公户字（1994）699号)“户口准迁证的使用范围：凡从外省市迁入我市的人员，除大中专院校录取和分配学生，军人复员转业，出境人员回国，劳改、劳教人员释放解教，仍按原有规定办理外，其他人员一律使用准迁证。”

附件:北京市公安局户政咨询电话.xls
附件:北京市公安局户政大厅办公时间.xlsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;按照提示操作即可&lt;/p&gt;

&lt;h2 id=&quot;action2原户籍地办理迁出&quot;&gt;action2:原户籍地办理迁出&lt;/h2&gt;
&lt;p&gt;材料:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;action1得到的迁入证明第二联&lt;/li&gt;
  &lt;li&gt;户口本&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;网上得到的信息,有的地方可以网上办理,材料邮寄,具体看迁入者的原户籍地情况.&lt;/p&gt;

&lt;h2 id=&quot;action3去北京的迁入派出所办理迁入&quot;&gt;action3:去北京的迁入派出所办理迁入&lt;/h2&gt;
&lt;p&gt;材料:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;action2拿到的迁出同意材料&lt;/li&gt;
  &lt;li&gt;action1得到的迁入证明第三联等材料(钉好的,千万不能开,开了报废)&lt;/li&gt;
  &lt;li&gt;夫妻双方户口本&lt;/li&gt;
  &lt;li&gt;夫妻双方身份证&lt;/li&gt;
  &lt;li&gt;夫妻双方结婚证&lt;/li&gt;
  &lt;li&gt;夫妻双方房产证&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;result拿到北京户口&quot;&gt;result:拿到北京户口&lt;/h2&gt;
&lt;p&gt;记得那天好好拾掇一下自己,因为要拍新的身份证照片了&lt;/p&gt;</content><author><name>Wit</name></author><category term="Life" /><summary type="html">背景 一些政府部门,企事业单位有政策,可以通过夫妻分居事由,解决户口问题. 下面说说具体步骤.</summary></entry><entry><title type="html">任取两个大于2的整数,互质的概率是多少</title><link href="https://abbywitmia.github.io/2021/09/28/euler-product-formula/" rel="alternate" type="text/html" title="任取两个大于2的整数,互质的概率是多少" /><published>2021-09-28T00:00:00+08:00</published><updated>2021-09-28T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/09/28/euler-product-formula</id><content type="html" xml:base="https://abbywitmia.github.io/2021/09/28/euler-product-formula/">&lt;hr /&gt;
&lt;h1 id=&quot;解&quot;&gt;解&lt;/h1&gt;
&lt;p&gt;首先, 易知(不严格地), 在大于2的整数中任性选一个数,则其为偶数的概率应该是&lt;br /&gt;
\(P_1=\frac{1}{2}\)&lt;br /&gt;
而在大于2的整数中任选两个数,则它们有公约数2(即两个数均为偶数)的概率应该是&lt;br /&gt;
\(P_2=P_1P_1=\frac{1}{2^2}\)&lt;br /&gt;
那么在大于2的整数中任选两个数,则它们没有公约数2的概率就是&lt;br /&gt;
\(P_{31}=1-P_2=1-\frac{1}{2^2}\)&lt;br /&gt;
同理,在大于2的整数中任选两个数,则它们没有公约数3的概率是&lt;br /&gt;
\(P_{32}=1-\frac{1}{3^2}\)&lt;br /&gt;
在大于2的整数中任选两个数,则它们没有公约数5的概率是&lt;br /&gt;
\(P_{33}=1-\frac{1}{5^2}\)&lt;br /&gt;
以此类推,在大于2的整数中任选两个数,则它们没有第k个素数公约数\(p_k\)的概率是&lt;br /&gt;
\(P_{3k}=1-\frac{1}{p_k^2}\)&lt;br /&gt;
而要是这两个数互质,则所有素数都应该不是它们的公约数.这样,它们除了1外再无公约数,因此,在大于2的整数中任选两个数,则它们互质的概率是&lt;br /&gt;
\(P=\prod_{k=1}^{\infty}(1-\frac{1}{p_k^2})\)&lt;br /&gt;
其中\(p_k\)为第k个素数.
而由Euler乘积公式可知&lt;br /&gt;
\(\prod_{k=1}^{\infty}(1-\frac{1}{p_k^s})^{-1}=\sum_{n=1}^{\infty}\frac{1}{n^s}=\zeta(s)\)&lt;br /&gt;
因此&lt;br /&gt;
\(P=(\sum_{n=1}^\infty \frac{1}{n^2})^{-1} =\frac{6}{\pi^2}\)&lt;br /&gt;
这一步可以看我讲解Basel Problem的&lt;a href=&quot;/2021/08/04/basel-problem/&quot;&gt;文章&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;证明&quot;&gt;证明&lt;/h1&gt;
&lt;p&gt;\(\zeta(s)=1+\frac{1}{2^s}+\frac{1}{3^s}+\cdots=\sum_{n=1}^{\infty}n^{-s} \tag{1}\)&lt;br /&gt;
两边同时乘以\(2^{-s}\)&lt;br /&gt;
\(\frac{1}{2^s}\zeta(s)= \frac{1}{2^s}+\frac{1}{4^s}+\frac{1}{6^s}+\cdots \tag{2}\)&lt;br /&gt;
(1)-(2)得&lt;br /&gt;
\((1-\frac{1}{2^s})\zeta(s)=1+\frac{1}{3^s}+\frac{1}{5^s}+\cdots\)&lt;br /&gt;
可以看出,操作后无穷和中含有素因子2的项被消去了,如法炮制&lt;br /&gt;
\((1-\frac{1}{3^s})(1-\frac{1}{2^s})\zeta(s)=1+\frac{1}{5^s}+\frac{1}{7^s}+\cdots\)&lt;br /&gt;
含有素因子3的项被消去,以此类推,进行无穷次类似操作&lt;br /&gt;
\(\cdots(1-\frac{1}{p_k^s})\cdots(1-\frac{1}{3^s})(1-\frac{1}{2^s})\zeta(s)=1\)&lt;br /&gt;
\(\zeta(s)=\sum_{n=1}^{\infty}n^{-s}=\prod_{k=1}^{\infty}(1-p_k^{-s})^{-1}\)&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">解 首先, 易知(不严格地), 在大于2的整数中任性选一个数,则其为偶数的概率应该是 \(P_1=\frac{1}{2}\) 而在大于2的整数中任选两个数,则它们有公约数2(即两个数均为偶数)的概率应该是 \(P_2=P_1P_1=\frac{1}{2^2}\) 那么在大于2的整数中任选两个数,则它们没有公约数2的概率就是 \(P_{31}=1-P_2=1-\frac{1}{2^2}\) 同理,在大于2的整数中任选两个数,则它们没有公约数3的概率是 \(P_{32}=1-\frac{1}{3^2}\) 在大于2的整数中任选两个数,则它们没有公约数5的概率是 \(P_{33}=1-\frac{1}{5^2}\) 以此类推,在大于2的整数中任选两个数,则它们没有第k个素数公约数\(p_k\)的概率是 \(P_{3k}=1-\frac{1}{p_k^2}\) 而要是这两个数互质,则所有素数都应该不是它们的公约数.这样,它们除了1外再无公约数,因此,在大于2的整数中任选两个数,则它们互质的概率是 \(P=\prod_{k=1}^{\infty}(1-\frac{1}{p_k^2})\) 其中\(p_k\)为第k个素数. 而由Euler乘积公式可知 \(\prod_{k=1}^{\infty}(1-\frac{1}{p_k^s})^{-1}=\sum_{n=1}^{\infty}\frac{1}{n^s}=\zeta(s)\) 因此 \(P=(\sum_{n=1}^\infty \frac{1}{n^2})^{-1} =\frac{6}{\pi^2}\) 这一步可以看我讲解Basel Problem的文章 证明 \(\zeta(s)=1+\frac{1}{2^s}+\frac{1}{3^s}+\cdots=\sum_{n=1}^{\infty}n^{-s} \tag{1}\) 两边同时乘以\(2^{-s}\) \(\frac{1}{2^s}\zeta(s)= \frac{1}{2^s}+\frac{1}{4^s}+\frac{1}{6^s}+\cdots \tag{2}\) (1)-(2)得 \((1-\frac{1}{2^s})\zeta(s)=1+\frac{1}{3^s}+\frac{1}{5^s}+\cdots\) 可以看出,操作后无穷和中含有素因子2的项被消去了,如法炮制 \((1-\frac{1}{3^s})(1-\frac{1}{2^s})\zeta(s)=1+\frac{1}{5^s}+\frac{1}{7^s}+\cdots\) 含有素因子3的项被消去,以此类推,进行无穷次类似操作 \(\cdots(1-\frac{1}{p_k^s})\cdots(1-\frac{1}{3^s})(1-\frac{1}{2^s})\zeta(s)=1\) \(\zeta(s)=\sum_{n=1}^{\infty}n^{-s}=\prod_{k=1}^{\infty}(1-p_k^{-s})^{-1}\)</summary></entry><entry><title type="html">Basel Problem的几何含义</title><link href="https://abbywitmia.github.io/2021/08/04/basel-problem/" rel="alternate" type="text/html" title="Basel Problem的几何含义" /><published>2021-08-04T00:00:00+08:00</published><updated>2021-08-04T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/04/basel-problem</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/04/basel-problem/">&lt;p&gt;原作者: 3Blue1Brown&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;1-序言&quot;&gt;1 序言&lt;/h1&gt;
&lt;p&gt;小时候学数学,第一次了解圆时,就被其简洁之美所吸引:一个变量(半径/直径)就可以定义一个圆  .
然而当我了解到圆周率π时,一种不”和谐”的感觉马上袭来.&lt;br /&gt;
一个不知道从哪里蹦出来的无理数–进一步来说,其实是超越数(不能作为有理系数多项式方程的根的数)–比√2感觉还无厘头.&lt;br /&gt;
√2通过一个简单的乘方运算即可得到”基本”的正整数,而π给我的感觉就是无迹可寻.&lt;br /&gt;
至于高中接触到自然对数的底e时,更是丈二和尚摸不到头脑–一堆材料完全是循环定义–可见我国之前的数学人才水平有多么单薄,连一个能把问题讲清讲透的基础教材都没有.&lt;br /&gt;
跑题了,收回来.然而长大后发现,其实π和e也没有那么难于理解.关于e的讲解可以看我转载的另一篇&lt;a href=&quot;/2021/08/03/e/&quot;&gt;文章&lt;/a&gt;.今天我们通过Basel-Problem来重新了解一下π.&lt;/p&gt;

&lt;h1 id=&quot;2-basel-problem简介&quot;&gt;2 Basel Problem简介&lt;/h1&gt;
&lt;p&gt;以下摘自百度百科&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;巴塞尔问题是一个著名的级数问题，这个问题首先由皮耶特罗·门戈利在1644年提出，由莱昂哈德·欧拉在1735年解决。
但当时他的证明还不是十分严密，真正严密的证明在1741年给出。
由于这个问题难倒了以前许多的数学家，欧拉一解出这个问题马上就出名了，当时他二十八岁。
欧拉把这个问题作了一番推广，他的想法后来被黎曼在1859年的论文《论小于给定大数的素数个数》（On the Number of Primes Less Than a Given Magnitude）中所采用，论文中定义了黎曼ζ函数，并证明了它的一些基本的性质。
这个问题是以瑞士的第三大城市巴塞尔命名的，它是欧拉和伯努利家族的家乡。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;看完不禁感慨,1735年西方的数学家就已经能解决这样的问题.而同年,写了《大义觉迷录》雍正帝驾崩,乾隆皇帝继位.&lt;br /&gt;
又跑题了,收回来.Basel Problem是求下面级数的值.&lt;br /&gt;
\(\sum_{n=1}^\infty \frac{1}{n^2} = \lim_{n \to +\infty} (1+\frac{1}{2^2}+\frac{1}{3^2}+\cdots+\frac{1}{n^2})\)&lt;br /&gt;
欧拉解决并证明了,解是\(\frac{\pi^2}{6}\)&lt;/p&gt;

&lt;p&gt;看完第一感觉,哇!π看起来不是那么”无厘头”了,而是很容易通过相对”基本”的计算得到,这让π看起来,”合理”了很多.&lt;/p&gt;

&lt;p&gt;然而这个解该如何理解呢?下面让我们给出一个几何理解.&lt;/p&gt;

&lt;h1 id=&quot;3-几何理解&quot;&gt;3 几何理解&lt;/h1&gt;
&lt;h2 id=&quot;31-转换为远近光源问题&quot;&gt;3.1 转换为远近光源问题&lt;/h2&gt;
&lt;p&gt;观察公式,可以发现,里面包含一个平方反比的关系.&lt;br /&gt;
学过中学物理的我们可以很容易联想起&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;牛顿万有引力定律&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;库伦定律&lt;/code&gt;.&lt;br /&gt;
从这个思路,我们可以假设有一个数轴,在每个正整数点上有一个相同的标准光源(亮度设定为1).&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/basel-problem/1.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
则Basel Problem可以转换为在原点的光线接收器接收的光线总亮度.&lt;br /&gt;
这一步比较好理解,但是似乎什么也没做.&lt;br /&gt;
别急,下面的思路是&lt;strong&gt;在不改变原点光线接收器接收的总亮度(问题的解)的前提下,重新调整光源分布并赋予其某种易于理解的几何意义&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;32-勾股定理的其他形式&quot;&gt;3.2 勾股定理的其他形式&lt;/h2&gt;
&lt;p&gt;下面引入一个引理&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/basel-problem/2.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
上图中在原点接收到的原始灯塔(与原点距离为h)的亮度等于A,B两灯塔之和&lt;br /&gt;
这是为什么呢?&lt;br /&gt;
因为勾股定理的另一个形式如下&lt;br /&gt;
\(\frac{1}{h^2} = \frac{1}{a^2} + \frac{1}{b^2}\)&lt;br /&gt;
证明如下&lt;br /&gt;
\(Area = \frac{1}{2}ab = \frac{1}{2}ch \quad \text{c是斜边长度} \\
a^2b^2=c^2h^2 \\
a^2b^2=(a^2+b^2)h^2 \\
\frac{1}{h^2} = \frac{1}{a^2} + \frac{1}{b^2}\)&lt;br /&gt;
如你所见,我们已经得到了一个方法,能够调整光源分布,我们离我们的目的又前进了一步.&lt;/p&gt;

&lt;h2 id=&quot;33-调整分布&quot;&gt;3.3 调整分布&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/2021/basel-problem/3.png&quot; alt=&quot;&quot; /&gt;
如上图,假设在一个周长为2的圆的一条直径的两端分别有一个灯塔和一个光线接收器.&lt;br /&gt;
易知&lt;br /&gt;
\(\text{直径长度为} \quad \frac{2}{\pi} \\
\text{则接收亮度为} \quad \frac{\pi^2}{4}\)&lt;/p&gt;

&lt;h2 id=&quot;331-第一次变换&quot;&gt;3.3.1 第一次变换&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/2021/basel-problem/4.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
如上图,我们接着画一个周长为4的圆.根据章节&lt;a href=&quot;#32-勾股定理的其他形式&quot;&gt;3.2&lt;/a&gt;,我们可以把原来的灯塔替换为新的圆上的两座灯塔.&lt;br /&gt;
注意:&lt;strong&gt;这里新的两座灯塔距离光线接收器的圆弧长度仍然为1&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;332-第二次变换&quot;&gt;3.3.2 第二次变换&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/2021/basel-problem/5.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
如上图,我们接着画一个周长为8的圆.&lt;br /&gt;
我们连接新的圆的圆心和原来的两座灯塔,两条连接线在新的圆上有4个交点.&lt;br /&gt;
我们在交点上放置新的灯塔.&lt;br /&gt;
由此我们可以把原来的在周长为4的圆上的两座灯塔替换为新的圆上的4座灯塔.&lt;br /&gt;
这是因为&lt;strong&gt;圆直径所对的圆周角总是直角&lt;/strong&gt;,所以章节&lt;a href=&quot;#32-勾股定理的其他形式&quot;&gt;3.2&lt;/a&gt;成立.&lt;br /&gt;
注意:&lt;strong&gt;这里新的4座灯塔把周长8的圆四等分,每段弧长为2&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;333-第三次变换&quot;&gt;3.3.3 第三次变换&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/2021/basel-problem/6.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
如上图,我们接着画一个周长为16的圆.我们可以把原来的在周长为8的圆上的4座灯塔替换为新的圆上的8座灯塔.&lt;br /&gt;
这里我们注意到规律,&lt;strong&gt;新画的圆上的灯塔总是”均匀”的分布,总是把新画的圆n等分&lt;/strong&gt;.&lt;br /&gt;
其实道理不难,我们注意到,新的圆的圆心总是在上一步操作的圆上,而且是在光线接收器所在直径的对面,再因为&lt;strong&gt;圆周角=圆心角的一半&lt;/strong&gt;,所以每次操作实际是把上次的角度折半,那么既然开始是’均匀’的,后续的操作都是’均匀’的.&lt;br /&gt;
这里我们注意到:&lt;strong&gt;由于我们每次变换,圆的周长增加一倍,灯塔数也增加一倍.所以相邻灯塔间的圆弧长度不变,始终为2&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;334-第次变换&quot;&gt;3.3.4 第∞次变换&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/2021/basel-problem/7.png&quot; alt=&quot;&quot; /&gt;
如上图,想象我们无穷次的进行变换,圆变得无穷大.&lt;br /&gt;
最后圆弧近似于一条直线.按照我们之前的发现,相邻灯塔的间隔是2, 可得&lt;br /&gt;
\(\cdots+\frac{1}{(-5)^2}+\frac{1}{(-3)^2}+\frac{1}{(-1)^2}+\frac{1}{1^2}+\frac{1}{3^2} +\frac{1}{5^2}+\cdots = \frac{\pi^2}{4}\)&lt;br /&gt;
现在我们已经得到了一种通过’基本’运算来得到π的方法,但是我们还没有得到Basel Problem的解.&lt;br /&gt;
不过这并不难,只需要一点简单的变化.&lt;br /&gt;
\(\cdots+\frac{1}{(-5)^2}+\frac{1}{(-3)^2}+\frac{1}{(-1)^2}+\frac{1}{1^2}+\frac{1}{3^2} +\frac{1}{5^2}+\cdots = \frac{\pi^2}{4} \\
\frac{1}{1^2}+\frac{1}{3^2} +\frac{1}{5^2}+\cdots= \frac{\pi^2}{8} \tag{1}\)&lt;/p&gt;

&lt;p&gt;\(\text{设x为Basel-Problem的解} \quad 1+\frac{1}{2^2}+\frac{1}{3^2}+\cdots = x \tag{2}\)&lt;br /&gt;
\(\text{则易知} \quad \frac{1}{2^2}+\frac{1}{4^2}+\frac{1}{6^2}+\cdots = \frac{x}{4} \tag{3}\)&lt;/p&gt;

&lt;p&gt;\(\text{(1)+(3)可得} \\
\frac{1}{1^2}+\frac{1}{2^2}+\frac{1}{3^2}+\frac{1}{4^2}+\frac{1}{5^2}+\cdots = \frac{\pi^2}{8} + \frac{x}{4} \tag{4}\)&lt;br /&gt;
\(\text{将(2)代入(4)可得} \\
x = \frac{\pi^2}{8} + \frac{x}{4} \\
\frac{3x}{4} = \frac{\pi^2}{8} \\
x = \frac{\pi^2}{6}\)&lt;/p&gt;

&lt;h1 id=&quot;4-感想&quot;&gt;4 感想&lt;/h1&gt;
&lt;p&gt;小的时候,听过一个曹冲称象的故事.&lt;br /&gt;
曹冲小小年纪就如此聪明,令人印象深刻.不过我理解曹冲称象关键是包含了人类的两大智慧.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;把一个未知问题转换为另外一个等价的问题&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;把转换的问题,分解为很多规模较小,易于解决的问题.最后再把子问题的解组合起来得到父问题的解&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;曹冲先把大象的重量转换为一船石头的重量&lt;br /&gt;
然后通过计算一堆堆石头的重量和来得到大象的重量&lt;/p&gt;

&lt;p&gt;本问题也是一样&lt;br /&gt;
我们先把问题转换为光源的问题&lt;br /&gt;
然后给了光源问题几何意义,得到一个易于理解的形式&lt;br /&gt;
最后通过简单的变换即可得到basel问题的解&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">原作者: 3Blue1Brown</summary></entry><entry><title type="html">数学常数e的含义</title><link href="https://abbywitmia.github.io/2021/08/03/e/" rel="alternate" type="text/html" title="数学常数e的含义" /><published>2021-08-03T00:00:00+08:00</published><updated>2021-08-03T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/03/e</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/03/e/">&lt;p&gt;作者： 阮一峰&lt;br /&gt;
日期： 2011年7月9日&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;1&quot;&gt;1&lt;/h1&gt;
&lt;p&gt;e是一个重要的常数，但是我一直不知道，它的真正含义是什么。&lt;br /&gt;
它不像π。大家都知道，π代表了圆的周长与直径之比3.14159，可是如果我问你，e代表了什么。你能回答吗？&lt;br /&gt;
维基百科说：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;e是自然对数的底数。&quot;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;但是，你去看”自然对数”，得到的解释却是：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;自然对数是以e为底的对数函数，e是一个无理数，约等于2.718281828。&quot;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这就构成了循环定义，完全没有说e是什么。数学家选择这样一个无理数作为底数，还号称这种对数很”自然”，这难道不是很奇怪的事情吗？&lt;/p&gt;

&lt;h1 id=&quot;2&quot;&gt;2&lt;/h1&gt;
&lt;p&gt;昨天我读到一篇&lt;a href=&quot;https://betterexplained.com/articles/an-intuitive-guide-to-exponential-functions-e/&quot;&gt;好文章&lt;/a&gt;，它把这个问题解释得非常清楚，而且一看就懂。&lt;br /&gt;
它说，什么是e？简单说，&lt;strong&gt;e就是增长的极限&lt;/strong&gt;。&lt;br /&gt;
下面就是它的解释。&lt;/p&gt;
&lt;h1 id=&quot;3&quot;&gt;3&lt;/h1&gt;
&lt;p&gt;假定有一种单细胞生物，它每过24小时分裂一次。&lt;br /&gt;
那么很显然，这种生物的数量，每天都会翻一倍。今天是1个，明天就是2个，后天就是4个。我们可以写出一个增长数量的公式：&lt;br /&gt;
\(growth = 2^x \qquad \text{x表示天数}\)&lt;br /&gt;
上式中的x就表示天数。这种生物在x天的总数，就是2的x次方。这个式子可以被改成下面这样：&lt;br /&gt;
\(growth =(1+100\%)^x\)&lt;br /&gt;
其中，1表示原有数量，100%表示单位时间内的增长率。&lt;/p&gt;
&lt;h1 id=&quot;4&quot;&gt;4&lt;/h1&gt;
&lt;p&gt;我们继续假定：每过12个小时，也就是分裂进行到一半的时候，新产生的那半个细胞已经可以再次分裂了。&lt;br /&gt;
因此，一天24个小时可以分成两个阶段，每一个阶段都在前一个阶段的基础上增长50%。&lt;br /&gt;
\(growth = (1+\frac{100\%}{2})^2 = 2.25\)&lt;br /&gt;
当这一天结束的时候，我们一共得到了2.25个细胞。其中，1个是原有的，1个是新生的，另外的0.25个是新生细胞分裂到一半的。&lt;br /&gt;
如果我们继续修改假设，这种细胞每过8小时就具备独立分裂的能力，也就是将1天分成3个阶段。&lt;br /&gt;
\(growth = (1+\frac{100\%}{3})^3 = 2.37037\cdots\)&lt;br /&gt;
那么，最后我们就可以得到大约2.37个细胞。&lt;br /&gt;
很自然地，如果我们进一步设想，这种分裂是连续不断进行的，新生细胞每分每秒都具备继续分裂的能力，那么一天最多可以得到多少个细胞呢？&lt;br /&gt;
\(growth = (1+\frac{100\%}{n})^n = ?\)&lt;br /&gt;
当n趋向无限时，这个式子的极值等于2.718281828…。&lt;br /&gt;
\(\lim_{n \to +\infty} (1+\frac{100\%}{n})^n =2.718281828\cdots\)&lt;br /&gt;
因此，当增长率为100%保持不变时，我们在单位时间内最多只能得到2.71828个细胞。&lt;strong&gt;数学家把这个数就称为e，它的含义是单位时间内，持续的翻倍增长所能达到的极限值&lt;/strong&gt;。&lt;br /&gt;
这个值是自然增长的极限，因此以e为底的对数，就叫做自然对数。&lt;/p&gt;
&lt;h1 id=&quot;5&quot;&gt;5&lt;/h1&gt;
&lt;p&gt;有了这个值以后，计算银行的复利就非常容易。&lt;br /&gt;
假定有一家银行，每年的复利是100%，请问存入100元，一年后可以拿多少钱？&lt;br /&gt;
\(\lim_{n \to +\infty} 100(1+\frac{100\%}{n})^n = 100e = 271.828\cdots\)&lt;br /&gt;
回答就是271.828元，等于100个e。&lt;br /&gt;
但是，实际生活中，银行的利息没有这么高，如果利息率只有5%，那么100元存一年可以拿到多少钱呢？&lt;br /&gt;
\(\lim_{n \to +\infty} 100(1+\frac{5\%}{n})^n = ?\)&lt;br /&gt;
为了便于思考，我们取n等于50：&lt;br /&gt;
\(100(1+\frac{5\%}{50})^{50} = 100(1+0.1\%)^{50}\)　　&lt;br /&gt;
我们知道，在100%利息率的情况下，n=1000所得到的值非常接近e：&lt;br /&gt;
\((1+\frac{100\%}{1000})^{1000} = (1+0.1\%)^{1000} \approx e\)&lt;br /&gt;
因此，5%利息率就相当于e的20分之一次方：&lt;br /&gt;
\((1+\frac{5\%}{50})^{50} = [(1+\frac{100\%}{1000})^{1000}]^{\frac{1}{20}} \approx e^\frac{1}{20}\)&lt;br /&gt;
20分之一正好等于5%的利率率，所以我们可以把公式改写成：&lt;br /&gt;
\(growth = e^{rate}\)&lt;br /&gt;
上式的rate就代表增长率。这说明e可以用于任何增长率的计算，前提是它必须是持续不断的复合式增长。&lt;/p&gt;
&lt;h1 id=&quot;6&quot;&gt;6&lt;/h1&gt;
&lt;p&gt;再考虑时间因素，如果把钱在银行里存2年，可以得到多少钱？&lt;br /&gt;
\(growth = (e^r)^2 = e^{2r}\)&lt;br /&gt;
在时间t的情况下，通用公式就是：&lt;br /&gt;
\(growth = = (e^r)^t = e^{rt}\)&lt;br /&gt;
上式就是计算增长量的万能公式，可以适用于任何时间、任何增长率。&lt;/p&gt;
&lt;h1 id=&quot;7&quot;&gt;7&lt;/h1&gt;
&lt;p&gt;回到上面的例子，如果银行的利息率是5%的复利，请问100元存款翻倍需要多少时间？&lt;br /&gt;
\(100 \cdot e^{5\%t} = 200\)&lt;br /&gt;
计算结果是13.86年：&lt;br /&gt;
\(t=\frac{ln2}{5\%} = \frac{0.693}{5\%} = \frac{69.3}{5} \approx \frac{72}{5}\)&lt;br /&gt;
上式最后一个等号，表明用72除以增长率，可以得到翻倍的大致时间，这就是&lt;a href=&quot;https://zh.wikipedia.org/wiki/72法則&quot;&gt;72法则&lt;/a&gt;的来源。&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">作者： 阮一峰 日期： 2011年7月9日</summary></entry><entry><title type="html">虚数的意义</title><link href="https://abbywitmia.github.io/2021/08/03/imaginary-number/" rel="alternate" type="text/html" title="虚数的意义" /><published>2021-08-03T00:00:00+08:00</published><updated>2021-08-03T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/03/imaginary-number</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/03/imaginary-number/">&lt;p&gt;作者： 阮一峰&lt;br /&gt;
日期： 2012年9月24日&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;有人在&lt;a href=&quot;https://math.stackexchange.com/questions/199676/what-are-imaginary-numbers&quot;&gt;Stack Exchange&lt;/a&gt;问了一个问题：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　&quot;我一直觉得虚数（imaginary number）很难懂。  
　　中学老师说，虚数就是-1的平方根。  
　　  
　　可是，什么数的平方等于-1呢？计算器直接显示出错！  
　　直到今天，我也没有搞懂。谁能解释，虚数到底是什么？  
　　它有什么用？&quot;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;帖子的下面，很多人给出了自己的解释，还推荐了一篇非常棒的文章&lt;a href=&quot;https://betterexplained.com/articles/a-visual-intuitive-guide-to-imaginary-numbers/&quot;&gt;《虚数的图解》&lt;/a&gt;。我读后恍然大悟，醍醐灌顶，原来虚数这么简单，一点也不奇怪和难懂！&lt;br /&gt;
下面，我就用自己的语言，讲述我所理解的虚数。&lt;/p&gt;
&lt;h1 id=&quot;一什么是虚数&quot;&gt;一、什么是虚数？&lt;/h1&gt;
&lt;p&gt;首先，假设有一根数轴，上面有两个反向的点：+1和-1。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/1.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
这根数轴的正向部分，可以绕原点旋转。显然，逆时针旋转180度，+1就会变成-1。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/2.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
这相当于两次逆时针旋转90度。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/3.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
因此，我们可以得到下面的关系式：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　(+1) * (逆时针旋转90度) * (逆时针旋转90度) = (-1)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果把+1消去，这个式子就变为：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　(逆时针旋转90度)^2 = (-1)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;将”逆时针旋转90度”记为 i ：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　i^2 = (-1)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个式子很眼熟，它就是虚数的定义公式。&lt;br /&gt;
所以，我们可以知道，&lt;strong&gt;虚数 i 就是逆时针旋转90度，i 不是一个数，而是一个旋转量&lt;/strong&gt;。&lt;/p&gt;
&lt;h1 id=&quot;二复数的定义&quot;&gt;二、复数的定义&lt;/h1&gt;
&lt;p&gt;既然 i 表示旋转量，我们就可以用 i ，表示任何实数的旋转状态。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/4.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
将实数轴看作横轴，虚数轴看作纵轴，就构成了一个二维平面。旋转到某一个角度的任何正实数，必然唯一对应这个平面中的某个点。&lt;br /&gt;
只要确定横坐标和纵坐标，比如( 1 , i )，就可以确定某个实数的旋转量（45度）。&lt;br /&gt;
数学家用一种特殊的表示方法，表示这个二维坐标：用 + 号把横坐标和纵坐标连接起来。比如，把 ( 1 , i ) 表示成 1 + i 。这种表示方法就叫做复数（&lt;strong&gt;complex number&lt;/strong&gt;），其中&lt;strong&gt;1 称为实数部，i 称为虚数部&lt;/strong&gt;。&lt;br /&gt;
为什么要把二维坐标表示成这样呢，下一节告诉你原因。&lt;/p&gt;
&lt;h1 id=&quot;三虚数的作用加法&quot;&gt;三、虚数的作用：加法&lt;/h1&gt;
&lt;p&gt;虚数的引入，大大方便了涉及到旋转的计算。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/5.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
比如，物理学需要计算”力的合成”。假定一个力是 3 + i ，另一个力是 1 + 3i ，请问它们的合成力是多少？&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/6.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
根据”平行四边形法则”，你马上得到，合成力就是 ( 3 + i ) + ( 1 + 3i ) = ( 4 + 4i )。&lt;br /&gt;
这就是虚数加法的物理意义。&lt;/p&gt;
&lt;h1 id=&quot;四虚数的作用乘法&quot;&gt;四、虚数的作用：乘法&lt;/h1&gt;
&lt;p&gt;如果涉及到旋转角度的改变，处理起来更方便。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/7.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
比如，一条船的航向是 3 + 4i 。&lt;br /&gt;
如果该船的航向，逆时针增加45度，请问新航向是多少？&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/8.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
45度的航向就是 1 + i 。计算新航向，只要把这两个航向 3 + 4i 与 1 + i 相乘就可以了（原因在下一节解释）：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　( 3 + 4i ) * ( 1 + i ) = ( -1 + 7i )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所以，该船的新航向是 -1 + 7i 。&lt;br /&gt;
如果航向逆时针增加90度，就更简单了。因为90度的航向就是 i ，所以新航向等于：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　( 3 + 4i ) * i = ( -4 + 3i )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这就是虚数乘法的物理意义：改变旋转角度。&lt;/p&gt;
&lt;h1 id=&quot;五虚数乘法的数学证明&quot;&gt;五、虚数乘法的数学证明&lt;/h1&gt;
&lt;p&gt;为什么一个复数改变旋转角度，只要做乘法就可以了？&lt;br /&gt;
下面就是它的数学证明，实际上很简单。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/imaginary_number/9.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
任何复数 a + bi，都可以改写成旋转半径 r 与横轴夹角 θ 的形式。&lt;br /&gt;
假定现有两个复数 a + bi 和 c + di，可以将它们改写如下：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　a + bi = r1 * ( cosα + isinα )  
　　c + di = r2 * ( cosβ + isinβ )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这两个复数相乘，( a + bi )( c + di ) 就相当于&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　r1 * r2 * ( cosα + isinα ) * ( cosβ + isinβ )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;展开后面的乘式，得到&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　cosα * cosβ - sinα * sinβ + i( cosα * sinβ + sinα * cosβ )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;根据三角函数公式，上面的式子就等于&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　cos(α+β) + isin(α+β)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所以，&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;　　( a + bi )( c + di )　＝　r1 * r2 * ( cos(α+β) + isin(α+β) )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这就证明了，两个复数相乘，就等于旋转半径相乘、旋转角度相加。&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">作者： 阮一峰 日期： 2012年9月24日</summary></entry><entry><title type="html">Martingale Arbitrage简介</title><link href="https://abbywitmia.github.io/2021/08/03/martingale-arbitrage/" rel="alternate" type="text/html" title="Martingale Arbitrage简介" /><published>2021-08-03T00:00:00+08:00</published><updated>2021-08-03T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/03/martingale-arbitrage</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/03/martingale-arbitrage/">&lt;h1 id=&quot;1-策略&quot;&gt;1 策略&lt;/h1&gt;
&lt;p&gt;一个赌场设有“猜大小”的赌局，玩家下注后猜“大”或者猜“小”，如果输了，则失去赌注，如果赢的话，则获得本金以及一倍的利润。 “必胜法”是这么玩的：&lt;/p&gt;

&lt;p&gt;（1）押100猜“大”；&lt;br /&gt;
（2）如果赢的话，返回（1）继续；&lt;br /&gt;
（3）如果输的话则将赌注翻倍后继续猜“大”，因为不可能连续出现“大”，总会有获胜的时候，而且由于赌注一直是翻倍，只要赢一次，就会把所有输掉的钱赢回；&lt;br /&gt;
（4）只要赢了，就继续返回（1）。&lt;/p&gt;

&lt;h1 id=&quot;2-实验&quot;&gt;2 实验&lt;/h1&gt;
&lt;p&gt;不妨先赌一把试试：&lt;br /&gt;
每局押 100 元，发哥带着 50000 的本金入场。&lt;br /&gt;
假设每局玩 1 分钟，那么每小时 60 次，每天可以玩 360 次。&lt;br /&gt;
那么第一天过去呢，看下发哥战绩如何呢？&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/martingale/1.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
天亮时，手里的钱已经有 67500 了，日入一万七，发哥觉得自己似乎找到了生命的真谛，一张丑脸上不禁泛起了微笑。&lt;/p&gt;

&lt;p&gt;哦对了，为了让我们的实验更加严谨，要先商量好，如果万一连续赌输，资金不够支持下一次赌注的时候，采取什么策略。&lt;/p&gt;

&lt;p&gt;这里采取的策略是：&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;下次赌注为全部余下资金，如果赌赢，那么回到（1）押100猜「大」&lt;/code&gt;&lt;br /&gt;
采取这种策略的原因是……这样编程比较方便。&lt;/p&gt;

&lt;p&gt;转眼又是一天过去了，来看下发哥今天战绩如何吧？&lt;/p&gt;

&lt;p&gt;咦，发哥你怎么不到天亮就回来了？&lt;br /&gt;
什么，输光光？！&lt;br /&gt;
到底发生了什么事？！&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/martingale/2.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
可以看到，从第 676 次时，发哥连续遇到了 10 次「小」， 好不容易积攒起来的 8 万财富毁于一旦。&lt;/p&gt;

&lt;p&gt;此处应该有掌声。&lt;/p&gt;

&lt;p&gt;痛定思痛，在排除了「赌场出老千」的因素以后，发哥总归还是不太甘心的……毕竟连续掷出 10 个「小」实在是很少见。&lt;/p&gt;

&lt;p&gt;由于本宇宙的资金已经耗尽，那么我们就派出平行宇宙的发哥再战一百回合吧！&lt;/p&gt;

&lt;p&gt;派出 100 个发哥荒野求生。&lt;/p&gt;

&lt;p&gt;20 年以后， 100 个中，能坚持自己梦想的有几人呢？&lt;/p&gt;

&lt;p&gt;结果出来了，先给众看官展示一下个人财富 Top 5 吧：&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/martingale/3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;然后放出大饼图：&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/martingale/4.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/martingale/5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如你所见，60% 的赌徒会在 5 天左右输光光，而半个月过后，还在继续的赌徒只剩 17% ，如果你足够努力，闯入三甲，那你账面上最多时会超过 100 万资金。&lt;/p&gt;

&lt;p&gt;前三甲以外的朋友们，在 50 天左右全部申请破产。&lt;/p&gt;

&lt;p&gt;另外，不得不提一下第一名这种不世出的天才，竟然坚持了 800 多天，巅峰期达到上千万，疯狂玷污实验数据……&lt;/p&gt;

&lt;p&gt;咳咳，所以说，实验结论就是，在统计数据明显不够充足的情况下（=_=），97% 的玩家在 50 天左右就输光，但与此同时，想依靠此路挣个上千万也不是没有可能的。&lt;/p&gt;

&lt;p&gt;另外，别忘了这是建立在输赢五五开、没有人出千、以及赌资不设上下限的情况下的。&lt;/p&gt;

&lt;h1 id=&quot;3-分析&quot;&gt;3 分析&lt;/h1&gt;
&lt;p&gt;实验做完了，下面开始分析：&lt;/p&gt;

&lt;p&gt;发哥初始资金带了 50000，每次押注 100，为了方便一点我们假设他带了51200 入场。&lt;/p&gt;

&lt;p&gt;这样，在 51200 ~ 102300 这个区间，如果连续掷 9 次「小」，就还能剩下 100 ~ 51100 。也就是说，虽然连续 10 次「小」才会输光，但是连续 9 次「小」，就已经让这个策略无法继续进行。&lt;/p&gt;

&lt;p&gt;过了这个节点，能承受的次数加 1 。&lt;/p&gt;

&lt;p&gt;根据之前的拟合方程，大概需要 (102300 – 51200) / 46.2 = 1106.06 次赌博&lt;/p&gt;

&lt;p&gt;然后，我们再算一下，平均需要掷多少次骰子，才会出现一个连续 9 个「小」？&lt;/p&gt;
&lt;h2 id=&quot;31-期望&quot;&gt;3.1 期望&lt;/h2&gt;
&lt;p&gt;让我们假设每一回合开始之前，都会有一个新的玩家加入游戏，与仍然在场的玩家们一同赌博。每个玩家最初都只有 1 元钱，并且他们的策略也都是相同的：每回都把当前身上的所有钱都押在正面上。运气好的话，从加入游戏开始，庄家抛掷出来的硬币一直是正面，这个玩家就会一直赢钱；如果连续 n 次硬币都是正面朝上，他将会赢得 2^n 元钱。这个 2^n 就是赌场老板的心理承受极限——一旦有人赢到了 2^n 元钱，赌场老板便会下令停止游戏，关闭赌场。让我们来看看，在这场游戏中存在哪些有趣的结论。&lt;br /&gt;
首先，连续n次正面朝上的概率虽然很小，但确实是有可能发生的，因此总有一个时候赌场将被关闭。赌场关闭之时，唯n赚到钱的人就是赌场关闭前最后进来的那 n 个人。每个人都只花费了 1 元钱，但他们却赢得了不同数量的钱。其中，最后进来的人赢回了 2 元，倒数第二进来的人赢回了 4 元，倒数第 n 进来的人则赢得了  2^n  元（他就是赌场关闭的原因），他们一共赚取了 2 + 4 + 8 + … + 2^n = 2^(n+1) - 2 元。其余所有人初始时的 1 元钱都打了水漂，因为没有人挺过了倒数第 n + 1 轮游戏。&lt;br /&gt;
另外，由于这个游戏是一个完全公平的游戏，因此赌场的盈亏应该是平衡的。换句话说，有多少钱流出了赌场，就该有多少的钱流进赌场。既然赌场的钱最终被赢走了 2^(n+1) - 2 元，因此赌场的期望收入也就是 2^(n+1) - 2 元。而赌场收入的唯一来源是每人 1 元的初始赌金，这就表明游戏者的期望数量是 2^(n+1) - 2 个。换句话说，游戏平均进行了 2^(n+1) - 2 次。再换句话说，平均抛掷 2^(n+1) - 2 次硬币才会出现 n 连正的情况。&lt;/p&gt;

&lt;p&gt;所以，出现 n 连「小」的时候，平均掷骰子的次数的期望为： 2^(n + 1) – 2 次。&lt;br /&gt;
连续掷 9 次都是「小」，平均需要掷 2^(9 + 1) – 2 = 1022 次。&lt;/p&gt;

&lt;p&gt;而根据之前的数据，资金能成长到可以承受连续 10 次「小」，需要约 1106.06 次。&lt;br /&gt;
也就是说，在黎明到来之前，通常已经出现了生命不可承受之重。&lt;/p&gt;

&lt;p&gt;即使你熬过了这个阶段，也无需骄傲，从 10 ~ 11 次的成长需要更久的时间，也带来了足够的几率将你打到。&lt;/p&gt;

&lt;h1 id=&quot;4-结论&quot;&gt;4 结论&lt;/h1&gt;
&lt;p&gt;此种策略，之所以看上去赢面非常大，实际上是因为一个非常容易忽略的原因，就是：&lt;br /&gt;
&lt;strong&gt;在这种条件下，一旦输，就是全部输光&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;换言之，这个游戏从「赢，得 100 ；输，失 100」，变为了「赢，得 100 ；输，失 50000」。&lt;/p&gt;

&lt;p&gt;赢面当然会变大！&lt;/p&gt;

&lt;p&gt;再说白一点,Martingale Arbitrage &lt;strong&gt;收益固定,风险几何级数增长&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;最后啰嗦一句：&lt;br /&gt;
&lt;strong&gt;珍惜生命，远离赌博&lt;/strong&gt;。&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">1 策略 一个赌场设有“猜大小”的赌局，玩家下注后猜“大”或者猜“小”，如果输了，则失去赌注，如果赢的话，则获得本金以及一倍的利润。 “必胜法”是这么玩的：</summary></entry><entry><title type="html">理解矩阵乘法</title><link href="https://abbywitmia.github.io/2021/08/02/matrix-multiplication/" rel="alternate" type="text/html" title="理解矩阵乘法" /><published>2021-08-02T00:00:00+08:00</published><updated>2021-08-02T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/02/matrix-multiplication</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/02/matrix-multiplication/">&lt;p&gt;大多数人在高中，或者大学低年级，都上过一门课《线性代数》。这门课其实是教矩阵。&lt;/p&gt;

&lt;p&gt;刚学的时候，还蛮简单的，矩阵加法就是相同位置的数字加一下。&lt;br /&gt;
\(\begin{pmatrix}
2&amp;amp;1\\\
4&amp;amp;3
\end{pmatrix} +
\begin{pmatrix}
1&amp;amp;2\\\
1&amp;amp;0
\end{pmatrix} =
\begin{pmatrix}
3&amp;amp;3\\\
5&amp;amp;3
\end{pmatrix}\)&lt;br /&gt;
矩阵减法也类似。&lt;br /&gt;
矩阵乘以一个常数，就是所有位置都乘以这个数。&lt;br /&gt;
\(2 \times
\begin{pmatrix}
2&amp;amp;1\\\
4&amp;amp;3
\end{pmatrix} =
\begin{pmatrix}
4&amp;amp;2\\\
8&amp;amp;6
\end{pmatrix}\)&lt;br /&gt;
但是，等到矩阵乘以矩阵的时候，一切就不一样了。&lt;br /&gt;
\(\begin{pmatrix}
2&amp;amp;1\\\
4&amp;amp;3
\end{pmatrix} \times
\begin{pmatrix}
1&amp;amp;2\\\
1&amp;amp;0
\end{pmatrix} =
\begin{pmatrix}
3&amp;amp;4\\\
7&amp;amp;8
\end{pmatrix}\)&lt;br /&gt;
这个结果是怎么算出来的？&lt;br /&gt;
教科书告诉你，计算规则是，第一个矩阵第一行的每个数字（2和1），各自乘以第二个矩阵第一列对应位置的数字（1和1），然后将乘积相加（ 2 x 1 + 1 x 1），得到结果矩阵左上角的那个值3。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/matrix/multiplication.gif&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
也就是说，结果矩阵第m行与第n列交叉位置的那个值，等于第一个矩阵第m行与第二个矩阵第n列，对应位置的每个值的乘积之和。&lt;br /&gt;
怎么会有这么奇怪的规则？&lt;br /&gt;
我一直没理解这个规则的含义，导致《线性代数》这门课就没学懂。研究生时发现，线性代数是向量计算的基础，很多重要的数学模型都要用到向量计算，所以我做不了复杂模型。这一直让我有点伤心。&lt;br /&gt;
前些日子，受到一篇文章的启发，我终于想通了，矩阵乘法到底是什么东西。关键就是一句话，矩阵的本质就是线性方程式，两者是一一对应关系。如果从线性方程式的角度，理解矩阵乘法就毫无难度。&lt;br /&gt;
下面是一组线性方程式。&lt;br /&gt;
\(\begin{cases}
2x+y=3\\
4x+3y=7
\end{cases}\)&lt;br /&gt;
矩阵的最初目的，只是为线性方程组提供一个简写形式。&lt;br /&gt;
\(\begin{pmatrix}
2&amp;amp;1\\\
4&amp;amp;3
\end{pmatrix}
\begin{pmatrix}
x\\\
y
\end{pmatrix} =
\begin{pmatrix}
3\\\
7
\end{pmatrix}\)&lt;br /&gt;
老实说，从上面这种写法，已经能看出矩阵乘法的规则了：系数矩阵第一行的2和1，各自与 x 和 y 的乘积之和，等于3。不过，这不算严格的证明，只是线性方程式转为矩阵的书写规则。&lt;br /&gt;
下面才是严格的证明。有三组未知数 x、y 和 t，其中 x 和 y 的关系如下。&lt;br /&gt;
\(\begin{cases}
a_{11}x_1+a_{12}x_2=y_1\\
a_{21}x_1+a_{22}x_2=y_2
\end{cases}\)&lt;br /&gt;
\(\begin{pmatrix}
a_{11}&amp;amp;a_{12}\\\
a_{21}&amp;amp;a_{22}
\end{pmatrix}
\begin{pmatrix}
x_1\\\
x_2
\end{pmatrix} =
\begin{pmatrix}
y_1\\\
y_2
\end{pmatrix}\)&lt;br /&gt;
x 和 t 的关系如下。&lt;br /&gt;
\(\begin{cases}
b_{11}t_1+b_{12}t_2=x_1\\
b_{21}t_1+b_{22}t_2=x_2
\end{cases}\)&lt;br /&gt;
\(\begin{pmatrix}
b_{11}&amp;amp;b_{12}\\\
b_{21}&amp;amp;b_{22}
\end{pmatrix}
\begin{pmatrix}
t_1\\\
t_2
\end{pmatrix} =
\begin{pmatrix}
x_1\\\
x_2
\end{pmatrix}\)  &lt;br /&gt;
有了这两组方程式，就可以求 y 和 t 的关系。从矩阵来看，很显然，只要把第二个矩阵代入第一个矩阵即可。&lt;br /&gt;
\(\begin{pmatrix}
a_{11}&amp;amp;a_{12}\\\
a_{21}&amp;amp;a_{22}
\end{pmatrix}
\begin{pmatrix}
b_{11}&amp;amp;b_{12}\\\
b_{21}&amp;amp;b_{22}
\end{pmatrix}
\begin{pmatrix}
t_1\\\
t_2
\end{pmatrix}=
\begin{pmatrix}
y_1\\\
y_2
\end{pmatrix}\)&lt;br /&gt;
从方程式来看，也可以把第二个方程组代入第一个方程组。&lt;br /&gt;
\(\begin{cases}
a_{11}(b_{11}t_1+b_{12}t_2)+a_{12}(b_{21}t_1+b_{22}t_2)=y_1\\
a_{21}(b_{11}t_1+b_{12}t_2)+a_{22}(b_{21}t_1+b_{22}t_2)=y_2
\end{cases}\)&lt;br /&gt;
上面的方程组可以整理成下面的形式。&lt;br /&gt;
\(\begin{cases}
(a_{11}b_{11}+a_{12}b_{21})t_1+(a_{11}b_{12}+a_{12}b_{22})t_2=y_1\\
(a_{21}b_{11}+a_{22}b_{21})t_1+(a_{21}b_{12}+a_{22}b_{22})t_2=y_2
\end{cases}\)&lt;br /&gt;
\(\begin{pmatrix}
a_{11}b_{11}+a_{12}b_{21}&amp;amp;a_{11}b_{12}+a_{12}b_{22}\\\
a_{21}b_{11}+a_{22}b_{21}&amp;amp;a_{21}b_{12}+a_{22}b_{22}
\end{pmatrix}
\begin{pmatrix}
t_1\\\
t_2
\end{pmatrix}=
\begin{pmatrix}
y_1\\\
y_2
\end{pmatrix}\)&lt;br /&gt;
最后那个矩阵等式，与前面的矩阵等式一对照，就会得到下面的关系。&lt;br /&gt;
\(\begin{pmatrix}
a_{11}&amp;amp;a_{12}\\\
a_{21}&amp;amp;a_{22}
\end{pmatrix}
\begin{pmatrix}
b_{11}&amp;amp;b_{12}\\\
b_{21}&amp;amp;b_{22}
\end{pmatrix}=
\begin{pmatrix}
a_{11}b_{11}+a_{12}b_{21}&amp;amp;a_{11}b_{12}+a_{12}b_{22}\\\
a_{21}b_{11}+a_{22}b_{21}&amp;amp;a_{21}b_{12}+a_{22}b_{22}
\end{pmatrix}\)&lt;br /&gt;
矩阵乘法的计算规则，从而得到证明。&lt;/p&gt;</content><author><name>Wit</name></author><category term="Math" /><summary type="html">大多数人在高中，或者大学低年级，都上过一门课《线性代数》。这门课其实是教矩阵。</summary></entry><entry><title type="html">TCP 协议简介</title><link href="https://abbywitmia.github.io/2021/08/02/tcp-introduction/" rel="alternate" type="text/html" title="TCP 协议简介" /><published>2021-08-02T00:00:00+08:00</published><updated>2021-08-02T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/02/tcp-introduction</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/02/tcp-introduction/">&lt;p&gt;作者： 阮一峰&lt;br /&gt;
日期： 2017年6月8日&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;TCP 是互联网核心协议之一，本文介绍它的基础知识。&lt;/p&gt;

&lt;h1 id=&quot;一tcp-协议的作用&quot;&gt;一、TCP 协议的作用&lt;/h1&gt;
&lt;p&gt;互联网由一整套协议构成。TCP 只是其中的一层，有着自己的分工。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/network-layer.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：TCP 是以太网协议和 IP 协议的上层协议，也是应用层协议的下层协议。）&lt;br /&gt;
最底层的以太网协议（Ethernet）规定了电子信号如何组成数据包（packet），解决了子网内部的点对点通信。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/network-topology.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：以太网协议解决了局域网的点对点通信。）&lt;br /&gt;
但是，以太网协议不能解决多个局域网如何互通，这由 IP 协议解决。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/ip.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：IP 协议可以连接多个局域网。）&lt;br /&gt;
IP 协议定义了一套自己的地址规则，称为 IP 地址。它实现了路由功能，允许某个局域网的 A 主机，向另一个局域网的 B 主机发送消息。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/router.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：路由器就是基于 IP 协议。局域网之间要靠路由器连接。）&lt;br /&gt;
路由的原理很简单。市场上所有的路由器，背后都有很多网口，要接入多根网线。路由器内部有一张路由表，规定了 A 段 IP 地址走出口一，B 段地址走出口二，……通过这套”指路牌”，实现了数据包的转发。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/route_table.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：本机的路由表注明了不同 IP 目的地的数据包，要发送到哪一个网口（interface）。）&lt;br /&gt;
IP 协议只是一个地址协议，并不保证数据包的完整。如果路由器丢包（比如缓存满了，新进来的数据包就会丢失），就需要发现丢了哪一个包，以及如何重新发送这个包。这就要依靠 TCP 协议。&lt;br /&gt;
简单说，TCP 协议的作用是，保证数据通信的完整性和可靠性，防止丢包。&lt;/p&gt;
&lt;h1 id=&quot;二tcp-数据包的大小&quot;&gt;二、TCP 数据包的大小&lt;/h1&gt;
&lt;p&gt;以太网数据包（packet）的大小是固定的，最初是1518字节，后来增加到1522字节。其中， 1500 字节是负载（payload），22字节是头信息（head）。&lt;br /&gt;
IP 数据包在以太网数据包的负载里面，它也有自己的头信息，最少需要20字节，所以 IP 数据包的负载最多为1480字节。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/tcp_datagram.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：IP 数据包在以太网数据包里面，TCP 数据包在 IP 数据包里面。）&lt;br /&gt;
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节，因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息，所以 TCP 负载实际为1400字节左右。&lt;br /&gt;
因此，一条1500字节的信息需要两个 TCP 数据包。HTTP/2 协议的一大改进， 就是压缩 HTTP 协议的头信息，使得一个 HTTP 请求可以放在一个 TCP 数据包里面，而不是分成多个，这样就提高了速度。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/data_frame.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：以太网数据包的负载是1500字节，TCP 数据包的负载在1400字节左右。）&lt;/p&gt;
&lt;h1 id=&quot;三tcp-数据包的编号seq&quot;&gt;三、TCP 数据包的编号（SEQ）&lt;/h1&gt;
&lt;p&gt;一个包1400字节，那么一次性发送大量数据，就必须分成多个包。比如，一个 10MB 的文件，需要发送7100多个包。&lt;br /&gt;
发送的时候，TCP 协议为每个包编号（sequence number，简称 SEQ），以便接收的一方按照顺序还原。万一发生丢包，也可以知道丢失的是哪一个包。&lt;br /&gt;
第一个包的编号是一个随机数。为了便于理解，这里就把它称为1号包。假定这个包的负载长度是100字节，那么可以推算出下一个包的编号应该是101。这就是说，每个数据包都可以得到两个编号：自身的编号，以及下一个包的编号。接收方由此知道，应该按照什么顺序将它们还原成原始文件。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/seq.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：当前包的编号是45943，下一个数据包的编号是46183，由此可知，这个包的负载是240字节。）&lt;/p&gt;
&lt;h1 id=&quot;四tcp-数据包的组装&quot;&gt;四、TCP 数据包的组装&lt;/h1&gt;
&lt;p&gt;收到 TCP 数据包以后，组装还原是操作系统完成的。应用程序不会直接处理 TCP 数据包。&lt;br /&gt;
对于应用程序来说，不用关心数据通信的细节。除非线路异常，收到的总是完整的数据。应用程序需要的数据放在 TCP 数据包里面，有自己的格式（比如 HTTP 协议）。&lt;br /&gt;
TCP 并没有提供任何机制，表示原始文件的大小，这由应用层的协议来规定。比如，HTTP 协议就有一个头信息&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length&lt;/code&gt;，表示信息体的大小。对于操作系统来说，就是持续地接收 TCP 数据包，将它们按照顺序组装好，一个包都不少。&lt;br /&gt;
操作系统不会去处理 TCP 数据包里面的数据。一旦组装好 TCP 数据包，就把它们转交给应用程序。TCP 数据包里面有一个端口（port）参数，就是用来指定转交给监听该端口的应用程序。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/port.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：系统根据 TCP 数据包里面的端口，将组装好的数据转交给相应的应用程序。上图中，21端口是 FTP 服务器，25端口是 SMTP 服务，80端口是 Web 服务器。）&lt;br /&gt;
应用程序收到组装好的原始数据，以浏览器为例，就会根据 HTTP 协议的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length&lt;/code&gt;字段正确读出一段段的数据。这也意味着，一次 TCP 通信可以包括多个 HTTP 通信。&lt;/p&gt;
&lt;h1 id=&quot;五慢启动和-ack&quot;&gt;五、慢启动和 ACK&lt;/h1&gt;
&lt;p&gt;服务器发送数据包，当然越快越好，最好一次性全发出去。但是，发得太快，就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话，发得越快，丢得越多。&lt;br /&gt;
最理想的状态是，在线路允许的情况下，达到最高速率。但是我们怎么知道，对方线路的理想速率是多少呢？答案就是慢慢试。&lt;br /&gt;
TCP 协议为了做到效率与可靠性的统一，设计了一个慢启动（slow start）机制。开始的时候，发送得较慢，然后根据丢包的情况，调整速率：如果不丢包，就加快发送速度；如果丢包，就降低发送速度。&lt;br /&gt;
Linux 内核里面&lt;a href=&quot;http://elixir.free-electrons.com/linux/v4.5/source/include/net/tcp.h#L220&quot;&gt;设定&lt;/a&gt;了（常量&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TCP_INIT_CWND&lt;/code&gt;），刚开始通信的时候，发送方一次性发送10个数据包，即”发送窗口”的大小为10。然后停下来，等待接收方的确认，再继续发送。&lt;br /&gt;
默认情况下，接收方每收到&lt;a href=&quot;https://serverfault.com/questions/348666/when-the-tcp-engine-decides-to-send-an-ack&quot;&gt;两个&lt;/a&gt; TCP 数据包，就要&lt;a href=&quot;https://stackoverflow.com/a/3604882/1194049&quot;&gt;发送&lt;/a&gt;一个确认消息。”确认”的英语是 acknowledgement，所以这个确认消息就简称 ACK。&lt;br /&gt;
ACK 携带两个信息。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;期待要收到下一个数据包的编号&lt;/li&gt;
  &lt;li&gt;接收方的接收窗口的剩余容量&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;发送方有了这两个信息，再加上自己已经发出的数据包的最新编号，就会推测出接收方大概的接收速度，从而降低或增加发送速率。这被称为”发送窗口”，这个窗口的大小是可变的。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/window.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：每个 ACK 都带有下一个数据包的编号，以及接收窗口的剩余容量。双方都会发送 ACK。）&lt;br /&gt;
注意，由于 TCP 通信是双向的，所以双方都需要发送 ACK。两方的窗口大小，很可能是不一样的。而且 ACK 只是很简单的几个字段，通常与数据合并在一个数据包里面发送。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/ack.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：上图一共4次通信。第一次通信，A 主机发给B 主机的数据包编号是1，长度是100字节，因此第二次通信 B 主机的 ACK 编号是 1 + 100 = 101，第三次通信 A 主机的数据包编号也是 101。同理，第二次通信 B 主机发给 A 主机的数据包编号是1，长度是200字节，因此第三次通信 A 主机的 ACK 是201，第四次通信 B 主机的数据包编号也是201。）&lt;br /&gt;
即使对于带宽很大、线路很好的连接，TCP 也总是从10个数据包开始慢慢试，过了一段时间以后，才达到最高的传输速率。这就是 TCP 的慢启动。&lt;/p&gt;
&lt;h1 id=&quot;六数据包的遗失处理&quot;&gt;六、数据包的遗失处理&lt;/h1&gt;
&lt;p&gt;TCP 协议可以保证数据通信的完整性，这是怎么做到的？&lt;br /&gt;
前面说过，每一个数据包都带有下一个数据包的编号。如果下一个数据包没有收到，那么 ACK 的编号就不会发生变化。&lt;br /&gt;
举例来说，现在收到了4号包，但是没有收到5号包。ACK 就会记录，期待收到5号包。过了一段时间，5号包收到了，那么下一轮 ACK 会更新编号。如果5号包还是没收到，但是收到了6号包或7号包，那么 ACK 里面的编号不会变化，总是显示5号包。这会导致大量重复内容的 ACK。&lt;br /&gt;
如果发送方发现收到三个连续的重复 ACK，或者超时了还没有收到任何 ACK，就会确认丢包，即5号包遗失了，从而再次发送这个包。通过这种机制，TCP 保证了不会有数据包丢失。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/tcp/timeout.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
（图片说明：Host B 没有收到100号数据包，会连续发出相同的 ACK，触发 Host A 重发100号数据包。）&lt;/p&gt;
&lt;h1 id=&quot;七参考链接&quot;&gt;七、参考链接&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.destroyallsoftware.com/compendium/network-protocols&quot;&gt;Network protocols for programmers who know at least one programming language&lt;/a&gt;&lt;/p&gt;</content><author><name>Wit</name></author><category term="Network" /><category term="TCP" /><summary type="html">作者： 阮一峰 日期： 2017年6月8日</summary></entry><entry><title type="html">哈希碰撞与生日攻击</title><link href="https://abbywitmia.github.io/2021/08/01/hash-collision/" rel="alternate" type="text/html" title="哈希碰撞与生日攻击" /><published>2021-08-01T00:00:00+08:00</published><updated>2021-08-01T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/01/hash-collision</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/01/hash-collision/">&lt;p&gt;作者： 阮一峰&lt;br /&gt;
日期： 2018年9月5日&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;一哈希碰撞是什么&quot;&gt;一、哈希碰撞是什么？&lt;/h1&gt;
&lt;p&gt;所谓哈希（hash），就是将不同的输入映射成独一无二的、固定长度的值（又称”哈希值”）。它是最常见的软件运算之一。&lt;br /&gt;
如果不同的输入得到了同一个哈希值，就发生了”哈希碰撞”（collision）。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/hash/collision.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
举例来说，很多网络服务会使用哈希函数，产生一个 token，标识用户的身份和权限。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AFGG2piXh0ht6dmXUxqv4nA1PU120r0yMAQhuc13i8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面这个字符串就是一个哈希值。如果两个不同的用户，得到了同样的 token，就发生了哈希碰撞。服务器将把这两个用户视为同一个人，这意味着，用户 B 可以读取和更改用户 A 的信息，这无疑带来了很大的安全隐患。&lt;br /&gt;
黑客攻击的一种方法，就是设法制造”哈希碰撞”，然后入侵系统，窃取信息。&lt;/p&gt;
&lt;h1 id=&quot;二如何防止哈希碰撞&quot;&gt;二、如何防止哈希碰撞？&lt;/h1&gt;
&lt;p&gt;防止哈希碰撞的最有效方法，就是扩大哈希值的取值空间。&lt;br /&gt;
16个二进制位的哈希值，产生碰撞的可能性是 65536 分之一。也就是说，如果有65537个用户，就一定会产生碰撞。哈希值的长度扩大到32个二进制位，碰撞的可能性就会下降到 4,294,967,296 分之一。&lt;br /&gt;
更长的哈希值意味着更大的存储空间、更多的计算，将影响性能和成本。开发者必须做出抉择，在安全与成本之间找到平衡。&lt;br /&gt;
下面就介绍，如何在满足安全要求的前提下，找出哈希值的最短长度。&lt;/p&gt;
&lt;h1 id=&quot;三生日攻击&quot;&gt;三、生日攻击&lt;/h1&gt;
&lt;p&gt;哈希碰撞的概率取决于两个因素（假设哈希函数是可靠的，每个值的生成概率都相同）。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;取值空间的大小（即哈希值的长度）&lt;/li&gt;
  &lt;li&gt;整个生命周期中，哈希值的计算次数&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个问题在数学上早有原型，叫做”生日问题”（birthday problem）：一个班级需要有多少人，才能保证每个同学的生日都不一样？
答案很出人意料。如果至少两个同学生日相同的概率不超过5%，那么这个班只能有7个人。事实上，一个23人的班级有50%的概率，至少两个同学生日相同；50人班级有97%的概率，70人的班级则是99.9%的概率（计算方法见后文）。&lt;br /&gt;
这意味着，如果哈希值的取值空间是365，只要计算23个哈希值，就有50%的可能产生碰撞。也就是说，哈希碰撞的可能性，远比想象的高。实际上，有一个近似的公式。&lt;br /&gt;
\(\sqrt {\frac{\pi}{2}N}\)&lt;br /&gt;
上面公式可以算出，50% 的哈希碰撞概率所需要的计算次数，N 表示哈希的取值空间。生日问题的 N 就是365，算出来是 23.9。这个公式告诉我们，哈希碰撞所需耗费的计算次数，跟取值空间的平方根是一个数量级。&lt;br /&gt;
这种利用哈希空间不足够大，而制造碰撞的攻击方法，就被称为生日攻击（birthday attack）。&lt;/p&gt;
&lt;h1 id=&quot;四数学推导&quot;&gt;四、数学推导&lt;/h1&gt;
&lt;p&gt;这一节给出生日攻击的数学推导。&lt;br /&gt;
至少两个人生日相同的概率，可以先算出所有人生日互不相同的概率，再用 1 减去这个概率。&lt;br /&gt;
我们把这个问题设想成，每个人排队依次进入一个房间。第一个进入房间的人，与房间里已有的人（0人），生日都不相同的概率是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;365/365&lt;/code&gt;；第二个进入房间的人，生日独一无二的概率是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;364/365&lt;/code&gt;；第三个人是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;363/365&lt;/code&gt;，以此类推。&lt;br /&gt;
因此，所有人的生日都不相同的概率，就是下面的公式。&lt;br /&gt;
\(\overline p(n) = 1 \cdot (1- \frac{1}{365}) \cdot (1- \frac{2}{365}) \cdots (1-\frac{n-1}{365})\)&lt;br /&gt;
上面公式的 n 表示进入房间的人数。可以看出，进入房间的人越多，生日互不相同的概率就越小。&lt;br /&gt;
这个公式可以推导成下面的形式。&lt;br /&gt;
\(\frac{365!}{365^n(365-n)!}\)&lt;br /&gt;
那么，至少有两个人生日相同的概率，就是 1 减去上面的公式。&lt;br /&gt;
\(p(n) = 1 - \overline p(n) = 1 - \frac{365!}{365^n(365-n)!}\)&lt;/p&gt;
&lt;h1 id=&quot;五哈希碰撞的公式&quot;&gt;五、哈希碰撞的公式&lt;/h1&gt;
&lt;p&gt;上面的公式，可以进一步推导成一般性的、便于计算的形式。&lt;br /&gt;
根据泰勒公式，指数函数 ex 可以用多项式展开。&lt;br /&gt;
\(exp(x) = \sum^{\infty}_{k=0}\frac{x^k}{k!} = 1 + x + \frac{x^2}{2} + \frac{x^3}{6} + \frac{x^4}{24} + \cdots\)&lt;br /&gt;
如果 x 是一个极小的值，那么上面的公式近似等于下面的形式。&lt;br /&gt;
\(e^x \approx 1+x\)&lt;br /&gt;
现在把生日问题的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1/365&lt;/code&gt;代入。&lt;br /&gt;
\(e^{-\frac{1}{365}} \approx 1 - \frac{1}{365}\)&lt;br /&gt;
因此，生日问题的概率公式，变成下面这样。&lt;br /&gt;
\(\begin{aligned}
\overline p(n) \approx 1 \cdot e^{-\frac{1}{365}} \cdot e^{-\frac{2}{365}} \cdots e^{-\frac{n-1}{365}} \\
= e^{-\frac{1+2+\cdots+n-1}{365}} = e^{-\frac{n(n-1)/2}{365}} = e^{-\frac{n(n-1)}{730}} \\
p(n) = 1 - \overline p(n) \approx 1 - e^{-\frac{n(n-1)}{730}}
\end{aligned}\)&lt;br /&gt;
假设 d 为取值空间（生日问题里是 365），就得到了一般化公式。&lt;br /&gt;
\(p(n, d) \approx 1 - e^{\frac{-n(n-1)}{2d}}\)&lt;br /&gt;
上面就是哈希碰撞概率的公式。&lt;/p&gt;
&lt;h1 id=&quot;六应用&quot;&gt;六、应用&lt;/h1&gt;
&lt;p&gt;上面的公式写成函数。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const calculate = (d, n) =&amp;gt; {
  const exponent = (-n * (n - 1)) / (2 * d)
  return 1 - Math.E ** exponent;
}

calculate(365, 23) // 0.5000017521827107
calculate(365, 50) // 0.9651312540863107
calculate(365, 70) // 0.9986618113807388
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一般来说，哈希值由大小写字母和阿拉伯数字构成，一共62个字符（10 + 26 + 26）。如果哈希值只有三个字符的长度（比如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abc&lt;/code&gt;），取值空间就是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;62 ^ 3 = 238,328&lt;/code&gt;，那么10000次计算导致的哈希碰撞概率是100%。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;calculate(62 ** 3, 10000) // 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;哈希值的长度增加到5个字符（比如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abcde&lt;/code&gt;），碰撞的概率就下降到5.3%。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;calculate(62 ** 5, 10000) // 0.05310946204730993
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;现在有一家公司，它的 API 每秒会收到100万个请求，每个请求都会生成一个哈希值，假定这个 API 会使用10年。那么，大约一共会计算300万亿次哈希。能够接受的哈希碰撞概率是1000亿分之一（即每天发生一次哈希碰撞），请问哈希字符串最少需要多少个字符？&lt;br /&gt;
根据上面的公式倒推，就会知道哈希值的最短长度是22个字符（比如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BwQ1W6soXkA1PU120r0yMA&lt;/code&gt;），计算过程略。&lt;br /&gt;
22个字符的哈希值，就能保证300万亿次计算里面，只有1000亿分之一的概率发生碰撞。常用的 SHA256 哈希函数产生的是64个字符的哈希值，每个字符的取值范围是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 ~ 9&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a ~ f&lt;/code&gt;，发生碰撞的概率还要低得多。&lt;/p&gt;
&lt;h1 id=&quot;七参考链接&quot;&gt;七、参考链接&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.freecodecamp.org/how-long-should-i-make-my-api-key-833ebf2dc26f&quot;&gt;How Long Should I Make My API Key?&lt;/a&gt;, by Sam Corcos&lt;br /&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Birthday_problem&quot;&gt;Birthday problem&lt;/a&gt;, by Wikipedia&lt;br /&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Birthday_attack&quot;&gt;Birthday attack&lt;/a&gt;, by Wikipedia&lt;/p&gt;</content><author><name>Wit</name></author><category term="Algorithm" /><category term="Math" /><summary type="html">作者： 阮一峰 日期： 2018年9月5日</summary></entry><entry><title type="html">JSON Web Token 入门教程</title><link href="https://abbywitmia.github.io/2021/08/01/jwt/" rel="alternate" type="text/html" title="JSON Web Token 入门教程" /><published>2021-08-01T00:00:00+08:00</published><updated>2021-08-01T00:00:00+08:00</updated><id>https://abbywitmia.github.io/2021/08/01/jwt</id><content type="html" xml:base="https://abbywitmia.github.io/2021/08/01/jwt/">&lt;p&gt;作者： 阮一峰&lt;br /&gt;
日期： 2018年7月23日&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;JSON Web Token（缩写 JWT）是目前最流行的跨域认证解决方案，本文介绍它的原理和用法。&lt;/p&gt;

&lt;h1 id=&quot;一跨域认证的问题&quot;&gt;一、跨域认证的问题&lt;/h1&gt;
&lt;p&gt;互联网服务离不开用户认证。一般流程是下面这样。&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;用户向服务器发送用户名和密码。&lt;/li&gt;
  &lt;li&gt;服务器验证通过后，在当前对话（session）里面保存相关数据，比如用户角色、登录时间等等。&lt;/li&gt;
  &lt;li&gt;服务器向用户返回一个 session_id，写入用户的 Cookie。&lt;/li&gt;
  &lt;li&gt;用户随后的每一次请求，都会通过 Cookie，将 session_id 传回服务器。&lt;/li&gt;
  &lt;li&gt;服务器收到 session_id，找到前期保存的数据，由此得知用户的身份。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这种模式的问题在于，扩展性（scaling）不好。单机当然没有问题，如果是服务器集群，或者是跨域的服务导向架构，就要求 session 数据共享，每台服务器都能够读取 session。&lt;br /&gt;
举例来说，A 网站和 B 网站是同一家公司的关联服务。现在要求，用户只要在其中一个网站登录，再访问另一个网站就会自动登录，请问怎么实现？&lt;br /&gt;
一种解决方案是 session 数据持久化，写入数据库或别的持久层。各种服务收到请求后，都向持久层请求数据。这种方案的优点是架构清晰，缺点是工程量比较大。另外，持久层万一挂了，就会单点失败。&lt;br /&gt;
另一种方案是服务器索性不保存 session 数据了，所有数据都保存在客户端，每次请求都发回服务器。JWT 就是这种方案的一个代表。&lt;/p&gt;
&lt;h1 id=&quot;二jwt-的原理&quot;&gt;二、JWT 的原理&lt;/h1&gt;
&lt;p&gt;JWT 的原理是，服务器认证以后，生成一个 JSON 对象，发回给用户，就像下面这样。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JSON&quot;&gt;{  
  &quot;姓名&quot;: &quot;张三&quot;,  
  &quot;角色&quot;: &quot;管理员&quot;,  
  &quot;到期时间&quot;: &quot;2018年7月1日0点0分&quot;  
}  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以后，用户与服务端通信的时候，都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据，服务器在生成这个对象的时候，会加上签名（详见后文）。&lt;br /&gt;
服务器就不保存任何 session 数据了，也就是说，服务器变成无状态了，从而比较容易实现扩展。&lt;/p&gt;
&lt;h1 id=&quot;三jwt-的数据结构&quot;&gt;三、JWT 的数据结构&lt;/h1&gt;
&lt;p&gt;实际的 JWT 大概就像下面这样。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/jwt/jwt.jpg&quot; alt=&quot;&quot; /&gt;
它是一个很长的字符串，中间用点（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;）分隔成三个部分。注意，JWT 内部是没有换行的，这里只是为了便于展示，将它写成了几行。&lt;br /&gt;
JWT 的三个部分依次如下。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Header（头部）&lt;/li&gt;
  &lt;li&gt;Payload（负载）&lt;/li&gt;
  &lt;li&gt;Signature（签名）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;写成一行，就是下面的样子。&lt;br /&gt;
&lt;img src=&quot;/images/posts/2021/jwt/jwt2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Header.Payload.Signature  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;下面依次介绍这三个部分。&lt;/p&gt;
&lt;h2 id=&quot;31-header&quot;&gt;3.1 Header&lt;/h2&gt;
&lt;p&gt;Header 部分是一个 JSON 对象，描述 JWT 的元数据，通常是下面的样子。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JSON&quot;&gt;{  
  &quot;alg&quot;: &quot;HS256&quot;,  
  &quot;typ&quot;: &quot;JWT&quot;  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alg&lt;/code&gt;属性表示签名的算法（algorithm），默认是 HMAC SHA256（写成 HS256）&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typ&lt;/code&gt;属性表示这个令牌（token）的类型（type），JWT 令牌统一写为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JWT&lt;/code&gt;&lt;br /&gt;
最后，将上面的 JSON 对象使用 Base64URL 算法（详见后文）转成字符串。&lt;/p&gt;
&lt;h2 id=&quot;32-payload&quot;&gt;3.2 Payload&lt;/h2&gt;
&lt;p&gt;Payload 部分也是一个 JSON 对象，用来存放实际需要传递的数据。JWT 规定了7个官方字段，供选用。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;iss (issuer)：签发人&lt;/li&gt;
  &lt;li&gt;exp (expiration time)：过期时间&lt;/li&gt;
  &lt;li&gt;sub (subject)：主题&lt;/li&gt;
  &lt;li&gt;aud (audience)：受众&lt;/li&gt;
  &lt;li&gt;nbf (Not Before)：生效时间&lt;/li&gt;
  &lt;li&gt;iat (Issued At)：签发时间&lt;/li&gt;
  &lt;li&gt;jti (JWT ID)：编号&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;除了官方字段，你还可以在这个部分定义私有字段，下面就是一个例子。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JSON&quot;&gt;{  
  &quot;sub&quot;: &quot;1234567890&quot;,  
  &quot;name&quot;: &quot;John Doe&quot;,  
  &quot;admin&quot;: true  
}  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意，JWT 默认是不加密的，任何人都可以读到，所以不要把秘密信息放在这个部分。&lt;br /&gt;
这个 JSON 对象也要使用 Base64URL 算法转成字符串。&lt;/p&gt;
&lt;h2 id=&quot;33-signature&quot;&gt;3.3 Signature&lt;/h2&gt;
&lt;p&gt;Signature 部分是对前两部分的签名，防止数据篡改。&lt;br /&gt;
首先，需要指定一个密钥（secret）。这个密钥只有服务器才知道，不能泄露给用户。然后，使用 Header 里面指定的签名算法（默认是 HMAC SHA256），按照下面的公式产生签名。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HMACSHA256(  
  base64UrlEncode(header) + &quot;.&quot; +  
  base64UrlEncode(payload),  
  secret)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;算出签名以后，把 Header、Payload、Signature 三个部分拼成一个字符串，每个部分之间用”点”（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;）分隔，就可以返回给用户。&lt;/p&gt;
&lt;h2 id=&quot;34-base64url&quot;&gt;3.4 Base64URL&lt;/h2&gt;
&lt;p&gt;前面提到，Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似，但有一些小的不同。&lt;br /&gt;
JWT 作为一个令牌（token），有些场合可能会放到 URL（比如 api.example.com/?token=xxx）。Base64 有三个字符&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt;，在 URL 里面有特殊含义，所以要被替换掉：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt;被省略、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;替换成&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;替换成&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_ &lt;/code&gt;。这就是 Base64URL 算法。&lt;/p&gt;
&lt;h1 id=&quot;四jwt-的使用方式&quot;&gt;四、JWT 的使用方式&lt;/h1&gt;
&lt;p&gt;客户端收到服务器返回的 JWT，可以储存在 Cookie 里面，也可以储存在 localStorage。&lt;br /&gt;
此后，客户端每次与服务器通信，都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送，但是这样不能跨域，所以更好的做法是放在 HTTP 请求的头信息&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization&lt;/code&gt;字段里面。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;另一种做法是，跨域的时候，JWT 就放在 POST 请求的数据体里面。&lt;/p&gt;
&lt;h1 id=&quot;五jwt-的几个特点&quot;&gt;五、JWT 的几个特点&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;JWT 默认是不加密，但也是可以加密的。生成原始 Token 以后，可以用密钥再加密一次。&lt;/li&gt;
  &lt;li&gt;JWT 不加密的情况下，不能将秘密数据写入 JWT。&lt;/li&gt;
  &lt;li&gt;JWT 不仅可以用于认证，也可以用于交换信息。有效使用 JWT，可以降低服务器查询数据库的次数。&lt;/li&gt;
  &lt;li&gt;JWT 的最大缺点是，由于服务器不保存 session 状态，因此无法在使用过程中废止某个 token，或者更改 token 的权限。也就是说，一旦 JWT 签发了，在到期之前就会始终有效，除非服务器部署额外的逻辑。&lt;/li&gt;
  &lt;li&gt;JWT 本身包含了认证信息，一旦泄露，任何人都可以获得该令牌的所有权限。为了减少盗用，JWT 的有效期应该设置得比较短。对于一些比较重要的权限，使用时应该再次对用户进行认证。&lt;/li&gt;
  &lt;li&gt;为了减少盗用，JWT 不应该使用 HTTP 协议明码传输，要使用 HTTPS 协议传输。
    &lt;h1 id=&quot;六参考链接&quot;&gt;六、参考链接&lt;/h1&gt;
    &lt;p&gt;&lt;a href=&quot;https://jwt.io/introduction/&quot;&gt;Introduction to JSON Web Tokens&lt;/a&gt;， by Auth0&lt;br /&gt;
&lt;a href=&quot;https://medium.com/@bryanmanuele/sessionless-authentication-withe-jwts-with-node-express-passport-js-69b059e4b22c&quot;&gt;Sessionless Authentication using JWTs (with Node + Express + Passport JS)&lt;/a&gt;, by Bryan Manuele&lt;br /&gt;
&lt;a href=&quot;https://github.com/dwyl/learn-json-web-tokens/blob/master/README.md&quot;&gt;Learn how to use JSON Web Tokens&lt;/a&gt;, by dwyl&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name>Wit</name></author><category term="JWT" /><category term="Algorithm" /><summary type="html">作者： 阮一峰 日期： 2018年7月23日</summary></entry></feed>