Re: 2^500

From
Alexandr A. Redchuck ()
To
Sergey Andrianov
Date
2002-09-24T09:27:38Z
Area
RU.ALGORITHMS
From: "Alexandr A. Redchuck" <real@real.kiev.ua>

19-Sep-02 08:00 Sergey Andrianov wrote to Vladislav Terehov:

VT>> Самый быстpый/самый компкактный (в плане пожиpания pесуpсов) алгоpитм, для
VT>> поэтапного вычисления и печати кусков сабжевого выpажения (2 в 500й
VT>> степени) на экpане в десятеpичной системе счисления кто подскажет?

SA>     Думаю, что "вычисление" здеесь излишне. Нужно просто перевести
SA> известное число
SA> (надеюсь понятно, почему 2^500 в двоичной системе вычислять не нужно) из
SA> одной
SA> системы счисления (двоичной, восьмеричной или шестнадцатиричной) в
SA> десятичную.
 Не могу не согласиться.

SA>     Для этого нужна процедура, умеющая находить частное и остаток двух
SA> длинных чисел.
 А это считаю абсолютно избыточным. Одно дело пользоваться для
преобразования /% при аппаратном делении нужной разрядности, а другое -
при программной реализации.
 В данном случае гораздо экономичнее вместо деления многозначных чисел
выполнять их умножение на 2 :-) Только что набросал, просьба не пинать за
вечерние корявости :-) (при небольшой доработке это дело сможет переводить
из двоичной формы в ascii числа произвольной длины).

int main( int ac, char **av) {
  int   p2 = 500;
  int   digits;
  char *string;
  int   i,j;

  if( ac >= 2 ) sscanf( av[1], "%d", &p2);
  if( p2<0 ) return 2;

  digits = (int)ceil(p2*log(2)/log(10));
  if( !digits) digits=1;
  string = (char*)malloc( digits+1);
  if( !string) {
     puts( "мало памяти");
     return 1;
  }
  // В массиве string[] одна десятичная цифра в байте
  // Если бы писать на асме, то можно было бы в одном байте держать
  // две двоично-десятичных цифры и ниже вместо if( .. >=10)
  // использовать команду двоично-десятичной коррекции после сложения,
  // было бы крепко быстрее

  memset( string, 0, digits+1); // заодно и концевой '\0'
  string[digits-1] = 1;         // 2^0
  j = p2; // p2 раз умножаем число в string[] на 2
  while( j--) {
     int carry=0;
     i=digits;
   // место для "небольшой доработки":
   // если бы переводили в десятичную форму не 2^p2, а произвольное число,
   // то тут надо было бы сделать сдвиг влево всего двоичного числа
   // и в carry выдвинуть старший его бит (т.е. возможный перенос 0 или 1)
     while( --i>=0) {
        string[i] = 2*string[i]+carry;
        carry = 0;
        if( string[i] >= 10 ) {
           carry = 1; // больше не бывает при умножении 1-значного
                      // десятичного числа на 2 при предыдущем переносе
                      // максимум 1.
           string[i] -= 10;
        }
     }
  }

  i=digits;
  while( --i >= 0) {  // переводим в ASCII наглым непортабельным образом.
     string[i]+='0';
  }

  printf( "2^%d=\n%s\n", p2, string);
  return 0;
}


wbr,
--
/* Alexandr Redchuck, Kyiv, Ukraine */
/* real на real тчк kiev тчк ua     */

--- ifmail v.2.15dev5
 * Origin: ReAl at home (2:5020/400)