Я просто вручил эту функцию в присвоении. Это сделано (следовательно никакой тег домашней работы). Но я хотел бы видеть, как это может быть улучшено.
По существу функция суммирует квадраты всех целых чисел между 1 и данное число, с помощью следующей формулы:
n(n+1)(2n+1)/6
Где n
максимальное количество.
Функция ниже сделана поймать любое переполнение и возвратиться 0, должен любой происходить.
UInt32 sumSquares(const UInt32 number)
{
int result = 0;
__asm
{
mov eax, number //move number in eax
mov edx, 2 //move 2 in edx
mul edx //multiply (2n)
jo end //jump to end if overflow
add eax, 1 //addition (2n+1)
jo end //jump to end if overflow
mov ecx, eax //move (2n+1) in ecx
mov ebx, number //move number in ebx
add ebx, 1 //addition (n+1)
jo end //jump to end if overflow
mov eax, number //move number in eax for multiplication
mul ebx //multiply n(n+1)
jo end //jump to end if overflow
mul ecx //multiply n(n+1)(2n+1)
jo end //jump to end if overflow
mov ebx, 6 //move 6 in ebx
div ebx //divide by 6, the result will be in eax
mov result, eax //move eax in result
end:
}
return result;
}
В основном я хочу знать то, что я могу улучшить там. С точки зрения лучших практик главным образом. Одна вещь звучит очевидной: более умная водосливная проверка (с единственной проверкой на любой максимальный вход вызвал бы переполнение).
mov eax, number //move number in eax
mov ecx, eax //dup in ecx
mul ecx //multiply (n*n)
jo end //jump to end if overflow
add eax, ecx //addition (n*n+n); can't overflow
add ecx, ecx //addition (2n); can't overflow
add ecx, 1 //addition (2n+1); can't overflow
mul ecx //multiply (n*n+n)(2n+1)
jo end //jump to end if overflow
mov ecx, 6 //move 6 in ebx
div ecx //divide by 6, the result will be in eax
mov result, eax //move eax in result
Снижение силы: сложите вместо умножения.
По результатам анализа меньше проверок переполнения (вы можете сделать лучше, как вы описали).
Хранить значения в регистрах вместо возврата к аргументу в стеке.
Тщательно выбирайте регистры, чтобы значения, которые можно использовать повторно, не перезаписывались.
mov eax, number ; = n
cmp eax, 0x928 ; cannot handle n >= 0x928
jnc end
shl eax, 1 ; = n(2)
add eax, 3 ; = n(2)+3
mov ebx, number
mul ebx ; = n(n(2)+3)
add eax, 1 ; = n(n(2)+3)+1
mov ebx, number
mul ebx ; = n(n(n(2)+3)+1) = n(n+1)(2n+1)
mov ebx, 6
div ebx
mov result, eax
Вместо проверки переполнения это решение проверяет ввод на соответствие известному максимальному значению, которое функция может справиться. Обратите внимание, что последнему умножению разрешено переполнение, и оно будет переполнено для любого входного числа
больше, чем 0x509
. Проверка по известному значению вместо того, чтобы полагаться на проверки переполнения, позволяет функции обрабатывать почти вдвое больше входных значений. Фактически, функция может обрабатывать каждый ввод, результат которого умещается в пределах 32 бит.
UInt32 sumSquares(const UInt32 number)
{
__asm
{
mov eax, number // n
cmd eax, MAX_VALUE
jg bad_value
lea ebx, [eax+1] // n + 1
lea ecx, [2*eax+1] // 2n + 1
mul ebx
mul ecx
shr eax, 1 // divide by 2
mov ebx, 2863311531 // inverse of 3
mul ebx // divide by 3
ret
bad_value:
xor eax, eax // return 0
ret
}
}
http://blogs.msdn.com/dev/archive/2005/12/12/502980.aspx
Spara