区间符号的概念出现在数学和计算机科学中。数学符号[、]、(、) 表示区间的域(或范围)。
-
括号[和]表示:
- 号码包含,
- 区间的这一边是封闭的,
-
括号(和)表示:
- 号码被排除,
- 区间的这一边是开放的。
混合状态的区间称为“半开”。
例如,从 1 .. 10(包括)的连续整数的范围将被 标记,如下所示:
注意inclusive 这个词是如何使用的。如果我们想排除端点但“覆盖”相同的范围,我们需要移动端点:
对于区间的左右边缘,实际上有 4 种排列:
(1,10) = 2,3,4,5,6,7,8,9 Set has 8 elements
(1,10] = 2,3,4,5,6,7,8,9,10 Set has 9 elements
[1,10) = 1,2,3,4,5,6,7,8,9 Set has 9 elements
[1,10] = 1,2,3,4,5,6,7,8,9,10 Set has 10 elements
这与数学和计算机科学有什么关系?
数组索引倾向于使用不同的偏移量,具体取决于您所在的字段:
- 数学往往是基于一个的。
- 某些编程语言往往是基于零的,例如 C、C++、Javascript、Python,而其他语言(例如 Mathematica、Fortran、Pascal)是从一开始的。
在实现数学算法(例如 for 循环)时,这些差异可能会导致细微的栅栏柱错误,也就是 off-by-one 错误。
整数
如果我们有一个集合或数组,比如前几个素数[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ],数学家会将第一个元素称为1st absolute 元素。即使用下标符号来表示索引:
相反,某些编程语言会将第一个元素称为zero'th relative 元素。
- a[0] = 2
- a[1] = 3
- :
- a[9] = 29
由于数组索引在 [0,N-1] 范围内,因此为了清楚起见,为范围 0 .. N 保持相同的数值是“不错的”,而不是添加文本 noise 比如-1 偏见。
例如,在 C 或 JavaScript 中,要遍历包含 N 个元素的数组,程序员将编写常见的 i = 0, i < N 习语,区间为 [0,N) 而不是稍微冗长的 [0,N-1 ]:
function main() {
var output = "";
var a = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ];
for( var i = 0; i < 10; i++ ) // [0,10)
output += "[" + i + "]: " + a[i] + "\n";
if (typeof window === 'undefined') // Node command line
console.log( output )
else
document.getElementById('output1').innerHTML = output;
}
<html>
<body onload="main();">
<pre id="output1"></pre>
</body>
</html>
由于数学家从 1 开始计数,因此他们会改用 i = 1, i <= N 命名法,但现在我们需要用从零开始的语言来更正数组偏移量。
例如
function main() {
var output = "";
var a = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ];
for( var i = 1; i <= 10; i++ ) // [1,10]
output += "[" + i + "]: " + a[i-1] + "\n";
if (typeof window === 'undefined') // Node command line
console.log( output )
else
document.getElementById( "output2" ).innerHTML = output;
}
<html>
<body onload="main()";>
<pre id="output2"></pre>
</body>
</html>
旁白:
在基于 0 的编程语言中,您可能需要一个虚拟零个元素的 kludge 才能使用基于 1 的数学算法。例如Python Index Start
浮点数
区间表示法对于浮点数也很重要,可以避免细微的错误。
在处理浮点数时,尤其是在计算机图形学(颜色转换、计算几何、动画缓动/混合等)中,通常会使用归一化数字。即 0.0 到 1.0 之间的数字。
如果端点是 inclusive 或 exclusive,了解边缘情况很重要:
- (0,1) = 1e-M .. 0.999...
- (0,1] = 1e-M .. 1.0
- [0,1) = 0.0 .. 0.999...
- [0,1] = 0.0 .. 1.0
其中 M 是一些 machine epsilon。这就是为什么您有时可能会在 C 代码(例如 1e-6)中看到 32 位浮点数的 const float EPSILON = 1e-# 习惯用法。这个 SO question Does EPSILON guarantee anything? 有一些初步的细节。如需更全面的答案,请参阅 FLT_EPSILON 和 David Goldberg 的 What Every Computer Scientist Should Know About Floating-Point Arithmetic
随机数生成器的某些实现,random() 可能会产生 0.0 .. 0.999... 范围内的值,而不是更方便的 0.0 .. 1.0。代码中正确的 cmets 会将其记录为 [0.0,1.0) 或 [0.0,1.0],因此在用法上没有歧义。
例子:
- 您想生成
random() 颜色。您将三个浮点值转换为无符号 8 位值,以生成分别具有红色、绿色和蓝色通道的 24 位像素。根据random() 输出的间隔,您最终可能会得到near-white (254,254,254) 或white (255,255,255)。
+--------+-----+
|random()|Byte |
|--------|-----|
|0.999...| 254 | <-- error introduced
|1.0 | 255 |
+--------+-----+
有关带间隔的浮点精度和鲁棒性的更多详细信息,请参阅 Christer Ericson 的 Real-Time Collision Detection,第 11 章 数值鲁棒性,第 11.3 节 鲁棒浮点使用。