Изчислете експонентите само чрез събиране

Пишем много проста програма за изпълнение на процесор, който сме създали за клас. Той няма способността да се умножава или дели. Ние обаче имахме поддръжка за събиране, изваждане и, или, и разклоняване за контрол на цикъла (като разклоняване при равни, ако сте запознати с MIPS). Мислехме, че една чиста програма, която да работи върху нея, ще бъде някакъв вид x^n програма. Разбира се, тези числа трябва да бъдат твърдо кодирани, но предвид ограниченията на нашия процесор, реалистично ли е?

Има ли изчисление само като добавяне за експоненти? Благодаря.


person powervillekittenkins    schedule 13.12.2009    source източник
comment
Ако имате инструкции за смяна, би било лесно да правите умножение и деление доста бързо.   -  person liori    schedule 14.12.2009
comment
Нямаме инструкции за смяна. Всъщност не са особено трудни и сега, като се замисля. Просто не е задължително.   -  person powervillekittenkins    schedule 14.12.2009


Отговори (6)


За малки цели числа, защо не?

Първо, приложете умножение, като използвате многократно добавяне. След това имплементирайте pow(), като използвате многократно умножение. Ще бъде бавно, но ще работи добре.

Съществува по-бърз алгоритъм за степенуване, наречен Постепенно степенуване. Въпреки това, като се има предвид, че нямате бързо умножение, не съм сигурен, че си заслужава - може да искате първо да работите върху прилагането на алгоритъм за бързо умножение.

person dmazzoni    schedule 13.12.2009
comment
Ако имате инструкции за битово изместване, можете по подобен начин да приложите по-бързо умножение чрез удвояване. - person Anon.; 14.12.2009
comment
Можете да приложите умножение чрез удвояване без инструкции за изместване на битове: a+a == a ‹‹ 1. :) - person Nick Johnson; 14.12.2009
comment
@Nick: Но без дясната смяна, как знаеш колко пъти да го направиш? - person Ben Voigt; 06.10.2015

В съответствие с отговора на dmazzoni в синтаксис в стил c:

int mulitply(int x, int y)
{
    int product;

    for (int i = 0; i<y; i++)
       product += x;

    return product;
}

int power(int x, int exponent)
{
    int result = 1;

    for (int i = 0; i < exponent; i++)
        result = multiply(result, x);

    return result;
}
person Brett Allen    schedule 13.12.2009
comment
опа, току-що разбрах, че съм разработил много подобно решение. +1 от мен все пак - person ram; 14.12.2009

Подобно на решението на Aequitarum, но използва многократно повдигане на квадрат за степени и многократно удвояване за умножения. Трябва да е по-бързо за големи x,y:

int multiply(int x, int y) {
  int product = 0;
  int bitmask = 1;

  while (y >= bitmask) {
    if (y & bitmask) product += x;
    x += x;
    bitmask += bitmask;
  }
  return product;
}

int power(int x, int exponent)
{
  int result = 1;
  int bitmask = 1;

  while (exponent >= bitmask) {
    if (exponent & bitmask) result = multiply(result, x);
    x = multiply(x, x);
    bitmask += bitmask;
  }
  return result;
}
person Keith Randall    schedule 14.12.2009

Много е реалистично. Не толкова много години назад процесорите нямаха ALU, което можеше да извършва каквито и да е разширени операции като умножение и деление.

Умножението обикновено се извършва чрез преместване и събиране. Ето малко псевдосглобяване:

; multiply registers a and b

; use c as high b
mov c,#0
; use d as low result
mov d,#0
; use e as high result
mov e,#0
.nextbit:
  ; shift low bit out of a
  shr a
  ; skip if zero
  bcc .noadd
    ; add b to result
    add d,b
    adc e,c
  .noadd:
  ; double b
  shl b
  rcl c
  ; test a
  cmp a,#0
bne .nextbit

(Имайте предвид, че резултатът от умножаването на двубайтови стойности е двубайтова стойност.)

След като имате умножение, можете просто да извършите цикъл, за да изчислите мощността.

използвани инструкции:

mov x,y = move y into x
shr x = shift right one bit
shl x = shift left one bit
rcl x = rotate left one bit with carry inserted
add x,y = add y to x
adc x,y = add y to x with carry
cmp x,y = compare x to y
bcc = branch on carry clear
bne = branch on not equal
#0 = literal number zero (as opposed to 0, which would be the address zero)
person Guffa    schedule 14.12.2009

Може да намерите статията в Уикипедия за Умножение ALU за подходяща. Със събиране и побитови операции (и и или) можете да реализирате умножение в една стъпка на бит, вместо да се налага да добавяте толкова пъти, колкото е големината на по-малкия оператор.

person Nick Johnson    schedule 14.12.2009

степен n на степен k:

exponent(n,k) {
   for(x=1..n)
      x = x + exponent(x,k-1)
}
person D_K    schedule 19.12.2009