<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>计算机 on 斐康明</title><link>https://young-mann.site/topics/%E8%AE%A1%E7%AE%97%E6%9C%BA/</link><description>Recent content in 计算机 on 斐康明</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Tue, 18 May 2021 19:31:10 +0800</lastBuildDate><atom:link href="https://young-mann.site/topics/%E8%AE%A1%E7%AE%97%E6%9C%BA/index.xml" rel="self" type="application/rss+xml"/><item><title>关系数据理论</title><link>https://young-mann.site/posts/note--armstrong-relations-for-dbms/</link><pubDate>Tue, 18 May 2021 19:31:10 +0800</pubDate><guid>https://young-mann.site/posts/note--armstrong-relations-for-dbms/</guid><description>&lt;p>本文是《数据库系统概论》的第6章以及“Database System: The Complete Book”的第三章所作的部分笔记，用以理解数据库设计过程中的关系数据理论。笔者认为，在这些教材中，对于关系数据理论的阐释可被归结为对于以下几个问题的回应：&lt;/p>
&lt;ul>
&lt;li>一个糟糕的数据库设计是什么样的，又会为使用者带来多少麻烦？&lt;strong>（问题的引入）&lt;/strong>&lt;/li>
&lt;li>是否存在某些可以遵循的准则，帮助我们设计出“不那么糟糕”的数据库？&lt;strong>（规范化理论）&lt;/strong>&lt;/li>
&lt;li>在了解“不那么糟糕的数据库应该是什么样的”之后，我们又能采取哪些措施，让我们在设计数据库时满足这些让数据库运作得更好的条件？&lt;strong>（Armstrong公理&amp;amp;模式分解）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="预备知识">预备知识&lt;/h2>
&lt;p>为了更好地理解下文的内容，读者首先需要掌握关系数据理论中的部分基本概念：&lt;/p>
&lt;h3 id="函数依赖functional-dependency">函数依赖(Functional Dependency)&lt;/h3>
&lt;ul>
&lt;li>函数依赖：设 R(U) 是属性集U的关系模型, X, Y是U的一个子集, 对于 R(U) 中的任一个关系 r, 不可能存在两个元组在 X 上属性值相同, 而在 Y 上属性值不同。则称 &lt;strong>X 函数确定 Y&lt;/strong> , 或 &lt;strong>Y 函数依赖 X&lt;/strong> ，记作$X \rightarrow Y$。&lt;/li>
&lt;li>完全函数依赖：如果Y函数依赖X，但不依赖X的任何一个真子集，则称&lt;strong>Y完全函数依赖X&lt;/strong>，记作$X \xrightarrow F Y$。&lt;/li>
&lt;li>部分函数依赖：如果Y函数依赖X，但依赖于X的任何一个真子集，则称&lt;strong>Y部分函数依赖X&lt;/strong>，记作$X \xrightarrow P Y$。&lt;/li>
&lt;li>传递函数依赖：设Z也是U的一个子集。如果X决定Y，Y决定Z，且&lt;strong>Y不决定X&lt;/strong>，那么称&lt;strong>Z对X传递函数依赖&lt;/strong>，记作$X \xrightarrow {传递} Y$。&lt;/li>
&lt;/ul>
&lt;h3 id="码键key">码/键(Key)&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>候选码：设属性集U包含关系模式内所有可能的属性值，K是U的子集，若$K\xrightarrow F U$，则称K为&lt;strong>候选码&lt;/strong>（K是一个集合！）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>主码：候选码若有多个，则选定其中的一个，称为&lt;strong>主码&lt;/strong>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>超码：对于属性集U，候选码K，若$K\xrightarrow P U$，则称K为&lt;strong>超码。&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>主属性/非主属性：包含在任何一个候选码的属性都叫&lt;strong>主属性&lt;/strong>，其他都叫&lt;strong>非主属性&lt;/strong>。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="范式normal-form">范式（Normal Form）&lt;/h3>
&lt;p>对于范式的概念，特别不靠谱的理解如下：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>第一范式(1NF)：不能出现类似excel中合并单元格的那种情形？（要求一个关系中的所有字段值都是不可分解的原子值）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>第二范式(2NF)：在满足1NF的基础上，还需要满足：在其他非主属性与主键的函数依赖关系中，主键集合中是作为&lt;strong>一个整体&lt;/strong>起到函数决定的作用的。反过来说，就是不能出现这样一种情况：主键中的某个主属性仅凭自身便能决定其它的非主属性，而函数决定其它的非主属性主键只有作为包含了（不存在非主属性对主键的部分函数依赖关系）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>第三范式(3NF)：在满足2NF的基础上，对于一个关系内的非主属性，他们能且仅能被主键唯一地表示。换而言之，该关系模式内存在的函数依赖关系都是由主键所决定的。除了这些被主键决定的函数依赖关系之外，非主属性之间必须相互独立，再也不能出现其他的函数依赖关系。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>BCNF: 在满足3NF的基础上，将“对于一个关系内的&lt;strong>非主&lt;/strong>属性，他们能且仅能被主键唯一地表示”成了“对于一个关系内的&lt;strong>所有&lt;/strong>属性，他们能且仅能被主键唯一地表示”，所需要满足的条件比3NF更加严格。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>第四范式(4NF)：原关系模式中不存在非平凡的多值依赖。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="问题的引入数据异常及规范化理论">问题的引入——数据异常及规范化理论&lt;/h2>
&lt;p>当我们在设计数据库时，若我们考虑不当，将过多的要素全部塞进了一张单独的表时，那么后续操作这张表时可能会引发诸多意料之外的异常情况(anomality)，如：&lt;/p></description></item><item><title>浮点数的取值范围</title><link>https://young-mann.site/posts/note--ieee-floating-point-range/</link><pubDate>Tue, 23 Feb 2021 22:58:40 +0800</pubDate><guid>https://young-mann.site/posts/note--ieee-floating-point-range/</guid><description>&lt;p>本文以单精度浮点格式（即C++中的float类型）为例，简要介绍 IEEE754 标准中浮点数的表示方法，以及该表示方法中需要特别注意的部分（即浮点数中的阶码是以移码形式存储的），并基于上述两点，求得单精度浮点数的有效数字的位数以及取值范围。其他类型浮点格式的有效数字位数及取值范围可依此类推。&lt;/p>
&lt;h2 id="前置知识">前置知识&lt;/h2>
&lt;p>若想了解浮点数在计算机内被如何存储，就必须先了解 IEEE754 标准，which 制定了计算机内浮点数及其运算的标准，被目前几乎所有的计算机所支持。&lt;/p>
&lt;h3 id="ieee754-标准">IEEE754 标准&lt;/h3>
$$
V=(-1)^s \times M \times 2^E
$$&lt;p>其中，&lt;/p>
&lt;ul>
&lt;li>V 表示所表示的浮点数的实际值&lt;/li>
&lt;li>s 为符号位(Sign)，表示该浮点数为正数或负数。若为正数，则 s 取值为0；若为负数，则 s 取值为1 (注：对于数值0的符号位需要特殊处理)&lt;/li>
&lt;li>M 为尾数(Mantissa)，是一个二进制小数，用于确定浮点数的精度，以定点数的形式存储在计算机内部（注意：此处的尾数的形式实为1.ffffff，而非0.fffffff，这个特征在下文讨论移码时会被重新提及）&lt;/li>
&lt;li>E 为阶码(Exponent)，用于对浮点数进行加权 (!!!注意!!!：阶码的取值可正可负，是一个有符号数，分别代表小数点是向左移还是向右移。出于使用上的便利，在存储阶码时用到了特别的方式，即下文即将提到的移码(Excess-N System) ）&lt;/li>
&lt;/ul>
&lt;p>将浮点数的位表示划分为三个字段，并分别对这些值进行编码，便可表示出浮点数的实际值。以单精度浮点格式为例。在单精度浮点格式中，符号位s、阶码E和尾数M的尾数分别为1位、8位和23位，将三者联立便可得到以32位表示出的浮点数，具体形式可参见下图：&lt;/p>
&lt;figure class="smaller">&lt;img src="https://young-mann.site/media/bOQYmsygdRkIa2q.jpg"
 alt="图源：Foundations of Computer Science (2018), Behrouz Forouzan">&lt;figcaption>
 &lt;p>图源：Foundations of Computer Science (2018), Behrouz Forouzan&lt;/p>
 &lt;/figcaption>
&lt;/figure>

&lt;h3 id="阶码的存储形式移码-excess-n-system">阶码的存储形式——移码 (Excess-N System)&lt;/h3>
&lt;h4 id="为啥不能用补码存储阶码">为啥不能用补码存储阶码？&lt;/h4>
&lt;p>在上文中我们提到，阶码 E 是一个有符号数，用于表示小数点需要向左或向右移动的位数。那么，在存储阶码时，根据此前所学的知识，我们自然会想到以补码 (2&amp;rsquo;s complement) 的形式存储阶码。&lt;/p>
&lt;p>但是，我们在课本上看到的阶码可不是用补码表示的。这是为什么呢？说实话，我不太确定真正的原因，现在能想到的理由如下：以补码表示的阶码会出现一个新的符号位（区别于上文 IEEE754 标准中所提到的符号位s），使得一个浮点数中出现两个符号位：浮点数本身的，以及浮点数阶码前的。这时，如果要对浮点数进行运算或者比较，无法采用整数那样的简单的二进制比较，所以算起来并不方便。&lt;/p>
&lt;h4 id="那有啥更好的方法存储阶码">那有啥更好的方法存储阶码？&lt;/h4>
&lt;p>既然不能用补码，那我们只能另辟蹊径了。回顾用补码表示阶码所产生的问题，可以发现，阶码作为有符号数时具备的符号位是引发麻烦的源头，那么为了方便起见，只能想着除去符号位了。基于这种思想，前人提出了&lt;strong>移码(Excess-N System)&lt;strong>的存储方式。简单而言，补码在存储阶码时所起到的作用，便是对于 作为有符号数的阶码 的所有可能取值，分别增加一个特定的值N（即$2^{m_E-1}-1$，也是上文中Excess-N中N的含义），从而将原本所有可能的取值映射到一个新的正数集合。基于该正数集合，我们可以找出与原阶码一一对应的无符号数。通过&lt;/strong>移码&lt;/strong>，我们不再需要考虑如何处理原本作为有符号数的阶码所包含的&lt;strong>符号位&lt;/strong>（因为阶码的所有可能取值已经被我们映射到了一个正整数集合）。因此，当我们需要对阶码进行运算或比较时，便可以将这些运算或比较先作用于新的整数集合上，再通过映射的逆操作得到我们所需的阶码值。&lt;/p>
&lt;h4 id="等等上面那个用于增加的值--是啥玩意儿">等等……上面那个用于增加的值 $2^{m_E-1}-1$ 是啥玩意儿？&lt;/h4>
&lt;p>至此，移码在阶码存储中的用途便讲得差不多了……不过，我是不是忘了什么？哦，在读上面那段的时候，你可能在想，那个$2^{m_E-1}-1$是啥？简单来说，这是将有符号数的阶码全部映射成正整数的一个比较合适的取值，其中$m_E$ 表示的是存储阶码可用的存储单元的位数，在单精度浮点格式里是8位。&lt;/p></description></item></channel></rss>