Delphi 等分其余部分 (MOD)

Delphi Division with equal splitting of the rest (MOD)

我有一个数学问题,我试图用 Delphi 函数来解决。我试图将一个整数分成(几乎)相等的部分。示例:

你有 10 个测试用例,你想分 3 个部分执行它们。因此,平衡工作负载的最佳方法是执行 3、3 和 4 而不是 1、1 和 8。

procedure calc_stream_numbers;
var div_res,rest:double;
    total,streams:integer;
begin
total := 10; 
streams := 3;
 div_res := total DIV streams;
 rest := total MOD streams;
 showmessage('Items: '  +IntToStr(total)+#13#10+
              'Streams: '+IntToStr(streams)+#13#10+
              'Result: '+FloatToStr(div_res)+
              'Rest: '+FloatToStr(rest));
end;

这给了我 10 / 3 = 3 (Rest 1) 的除法结果,所以我可以执行 3 x 3 个测试用例,总共有 9 个。要执行全部 10 个,我必须将剩余的一个添加到 3 个流中的任何一个。但是如果你有一个更复杂的例子..

我确定有一个数学表达式可以解决这个问题,但我必须承认,我没有任何线索。也许你能告诉我这样的划分是如何调用的,是否有任何内置的delphi函数。

此函数将计算一个整数数组,其中包含每个测试用例的平衡工作负载。

function SplitInteger(Value: Integer; divisor: Integer): TArray<Integer>;
var
  d,i : Integer;
begin
  SetLength(Result,divisor);
  if (divisor = 0) then
    Exit;
  d := Value div divisor;
  for i := 0 to divisor - 1 do
    Result[i] := d;
  // Fill up with the remains
  for i := 0 to (value mod divisor) - 1 do
    Inc(Result[i]); 
end;

你可以这样编码:

function BalancedWorkload(Total, Count: Integer): TArray<Integer>;
var
  i: Integer;
begin
  SetLength(Result, Count);
  for i := 0 to Count-1 do
  begin
    Result[i] := Total div Count;
    dec(Total, Result[i]);
    dec(Count);
  end;
end;

您有 Total 个单元可以分成 Count 个部分。我们从第一项 Total div Count 开始。然后我们还剩下 Total - (Total div Count) 个单元,需要拆分成 Count - 1 个部分。以此类推,直到无事可做为止。

这个算法可以很容易地写成递归的方式,但上面的迭代方法对我来说似乎更简单。


您的整个方法假设您可以提前预测每项任务需要多长时间。但是,如果出于某种原因,某些任务比其他任务花费的时间更长怎么办?那么你的方法将不会有效。更好的方法是拥有一个线程安全的任务队列。让每个消费者从队列中拉取任务并处理它们,直到没有任务剩余。

这里是:http://en.wikipedia.org/wiki/Bresenham's_line_algorithm

一个维度是工作量,另一个维度是工人数量


好吧,2D 图形的目标是吸引眼球,因此要在 "short" 个部分中公平地分配 "long" 个部分。 在您的情况下,我们可以将所有 "long" 个偏向一端。

function SplitIntoEqualParts(Total, Count: Integer): TArray<Integer>;
var
  i: Integer;
  delta, delta1, extra: Word;
begin
  Assert( Count < High(Word) ); // RTL DivMod limitation
  SetLength(Result, Count);

  DivMod(Total, Count, delta, extra); 
  // one division operation is 2 times faster than two separate operations :-D
  delta1 := Succ(delta);      

  for i := 0 to extra-1 do 
    Result[i] := delta1;    
  for i := extra to Count-1 do 
    Result[i] := delta;    
end;