根据符号而不是(“无条件”)“添加abs()”来添加或减去(未修改的)差异可能会也可能不会更有效。
不过,我希望当代编译器,甚至是 JIT 能够检测到等价性。
! Sum of Absolute Differences between every pair of elements of two arrays;
INTEGER PROCEDURE SAD2(a, b);
INTEGER ARRAY a, b;
BEGIN
INTEGER sum, i, j; ! by the book, declare j locally just like diff;
sum := 0;
FOR i := LOWERBOUND(a, 1) STEP 1 UNTIL UPPERBOUND(a, 1) DO
FOR j := LOWERBOUND(b, 1) STEP 1 UNTIL UPPERBOUND(b, 1) DO BEGIN
INTEGER diff;
diff := a(i) - b(j);
sum := if diff < 0 then sum - diff
else sum + diff;
END;
SAD2 := sum;
END SAD2;
关于二次算法,请参阅גלעד ברקן's answer。
这很可能是 גלעד ברקן 意图的代码,而不是遵循 PEP8 到点:
''' Given sequences A and B, SAD2 computes the sum of absolute differences
for every element b from B subtracted from every element a from A.
The usual SAD sums up absolute differences of pairs with like index, only.
'''
from bisect import bisect_right
class state(list):
''' Hold state for one sequence: sorted elements & processing state. '''
def __init__(self, a):
self.extend(sorted(a))
self.total = 0
''' sum(self[:self.todo]) '''
self.todo = 0
''' next index to do/#elements done '''
def __str__(self):
return list.__str__(self) + str(self.todo) + ', ' + str(self.total)
def SAD2(a, b):
''' return Sum of Absolute Differences of all pairs (a[x], b[y]). '''
nPairs = len(a) * len(b)
if nPairs < 2:
return abs(a[0] - b[0]) if 0 < nPairs else None
a = state(a)
b = state(b)
sad = 0
while True:
key = a[a.todo]
identical = bisect_right(a, key, a.todo)
local = 0
# iterate 'til not lower
# going to need i: no takewhile(lambda x: x < key, b[todo:])
i = b.todo
while i < len(b):
val = b[i]
if key <= val:
break
local += val
i += 1
# update SAD
# account for elements in a[:a.todo] paired with b[b.todo:i]
sad += local*a.todo - a.total*(i - b.todo)
b.todo = i
n_key = identical - a.todo
local += b.total
b.total = local
# account for elements in a[a.todo:identical] paired with b[:i]
sad += (key*i - local)*n_key
if len(b) <= b.todo:
rest = len(a) - identical
if 0 < rest:
sad += sum(a[identical:])*len(b) - b.total*rest
return sad
a.todo = identical
a.total += key * n_key
a, b = b, a