为什么我不能在for循环中使用Int64?

8

我可以为整数值编写for..do过程,但是我无法为int64值编写它。 例如:

var
  i:int64;
begin
  for i:=1 to 1000 do 
end; 

编译器拒绝编译这个,为什么会拒绝?

我看不到错误。同时程序无法启动。 - musti
2
+1 是因为这是一个学术问题,我看到了某种行为。我本来以为它会起作用,但实际上并没有……我想知道为什么。这不是那种“我真的需要在我的循环中执行数万亿次迭代”的问题。 - Johan
从学术角度来看,你可以提出一个有说服力的论点,即你应该始终使用“while”循环。 - paulsm4
编译器会默默地卡在这段代码上吗? - OnTheFly
4个回答

9

Delphi编译器目前还不支持Int64循环计数器。


5
for 循环 中,循环计数器必须是整数(或更小的类型)。这是为了加快 for 循环的执行速度所作的优化。
在内部,Delphi 总是使用 Int32,因为在 x86 上这是可用的最快数据类型。这在手册的某处有记录,但我现在没有链接。
如果您一定需要一个 64 位的循环计数器,请使用 while..do 循环或 repeat..until 循环。

3

即使编译器在Delphi 7的for循环中允许"int64"(Delphi 7???),它可能直到太阳死亡后才能完成完整的迭代。

那你为什么不只是使用“integer”呢?

如果您必须使用int64值...则可以使用“while”循环。

问题解决:)


但我必须这样做。因为我正在使用字符串,其长度为30亿。我该如何编写这个代码:for i:=1到30000000000? - musti
使用 while 循环,例如:var I: Int64; I := 1; while I <= 30000000000 do begin ...; Inc(I); end; - Remy Lebeau
1
30亿个字符的字符串?听起来非常奇怪且难以处理。 - Mike Bailey
5
Delphi 7是32位的,因此你关于字符串长度的断言是不正确的。 - David Heffernan
1
也许一次只分析一个人类染色体?顺便问一下,如果是30亿,为什么上面的数字有10个零? - Argalatyr
1
我投票反对这个答案,因为它甚至没有涉及问题的主题(“为什么…”),只是说“不要那样做”,然后绕过去了。 - OnTheFly

2

为什么在for循环中要使用Int64?

很容易回答:

  • 没有必要进行大量迭代才需要Int64,只需从5E9到5E9 + 2(总共三次迭代)进行循环即可。
  • 这只是迭代值比Int32可以容纳的更大而已。

一个例子:

procedure Why_Int64_Would_Be_Great_On_For_Loop;
const
     StartValue=5000000000; // Start form 5E9, 5 thousand millons
     Quantity=10; // Do it ten times
var
   Index:Int64;
begin
     for Index:=StartValue to StartValue+Quantity-1
     do begin // Bla bla bla
             // Do something really fast (only ten times)
       end;
end;

那段代码并不需要很长时间,只是索引值需要超过32位整数的限制。

解决方法是使用while循环:

procedure Equivalent_For_Loop_With_Int64_Index;
const
     StartValue=5000000000; // Start form 5E9, 5 thousand millons
     Quantity=10; // Do it ten times
var
   Index:Int64;
begin
     Index:=StartValue;
     while Index<=StartValue+Quantity
     do begin // Bla bla bla
             // Do something really fast (only ten times)
             Inc(Index);
       end;
end;

因此,为什么编译器拒绝编译foor循环,我看不出真正的原因...任何for循环都可以自动转换成while循环...并且预编译器可以在编译器之前执行此操作(就像执行的其他优化一样)...我看到的唯一原因是创建编译器的懒惰人没有考虑到它。
如果for被优化了,因此只能使用32位索引,那么如果代码尝试使用64位索引,则无法进行优化,那么为什么不让预编译器优化器替我们更改呢...这只会给程序员带来不良印象!!!
我不想使任何人生气...
我只是说一些显而易见的事情...
顺便说一句,并不是所有人都从零(或一)值开始进行for循环...有时需要从非常大的值开始。
总是说,如果您需要执行固定次数的操作,最好使用for循环而不是while循环...
还可以说一些内容...使用Inc(Index)的for-loop和while-loop这两个版本同样快...但是如果将while-loop步骤设置为Index:= Index+1;它会变慢;但实际上它并不会变慢,因为预编译器优化器会看到这一点并使用Inc(Index)代替...您可以通过执行以下操作来查看:
// I will start the loop from zero, not from two, but i first do some maths to avoid pre-compiler optimizator to convert Index:=Index+Step; to Inc(Index,Step); or better optimization convert it to Inc(Index);
Index:=2; 
Step:=Index-1; // Do not put Step:=1; or optimizator will do the convertion to Inc()
Index:=Step-2; // Now fix, the start, so loop will start from zero
while Index<1000000 // 1E6, one millon iterations, from 0 to 999999
do begin
        // Do something
        Index:=Index+Step; // Optimizator will not change this into Inc(Index), since sees that Step has changed it's value before
   end;

优化器可以看到一个变量不改变其值,所以它可以将其转换为常量,然后在增量赋值时,如果添加一个常量(variable:=variable+constant),它将优化为Inc(variable,constant),如果它看到这样的常量是1,它也会将其优化为Inc(variable)...在低级计算机语言中,这种优化非常明显...
在低级计算机语言中: 普通的加法(variable:=variable1+variable2)意味着两个内存读取加上一次求和加上一次内存写入...很多工作 但如果是(variable:=variable+othervariable),它可以通过将variable保留在处理器缓存中进行优化。 同样,如果是(variable:=variable1+constant),它也可以通过将常量保存在处理器缓存中进行优化。 如果(variable:=variable+constant),两者都被缓存在处理器缓存中,所以与其他选项相比速度非常快,不需要访问RAM。
这样预编译优化器又做了另一个重要的优化...for循环索引变量被保存为处理器寄存器...比处理器缓存更快...
大多数主处理器也进行了额外的优化(在处理器内部的硬件级别上)...一些缓存区域(对于我们来说是32位变量)被认为是密集使用的,因此被存储为特殊寄存器以加快访问速度...而for循环/while循环的索引就是其中之一...但如我所说...大多数使用MP技术的AMD处理器都这样做...我还不知道任何Intel这样做!这种优化在多核和超级计算中更为重要...所以也许这就是AMD有它而Intel没有的原因!
我只想展示一个“为什么”,还有很多其他的原因...另一个可能很简单,比如索引存储在数据库Int64字段类型中,等等...我知道有很多原因,还有更多我还不知道...
我希望这将有助于理解需要对Int64索引进行循环的原因,以及如何通过正确有效地将循环转换为while循环来实现而不会失去速度。
注意:对于x86编译(不适用于64位编译),请注意Int64在内部作为两个Int32部分进行管理...当修改值时,有额外的代码需要执行,在添加和减少上非常低,但在乘法或除法上,这种额外的代码是明显的...但如果你真的需要Int64,你就需要它,那还能怎么办...想象一下如果你需要float或double,等等...!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接