Чистое изменение базы

Я пытаюсь (без особого успеха) написать короткую функцию на C ++:

двойная цифра (double x, int b, int d)

который возвращает d-ю цифру в разложении по основанию b числа x, которое может быть положительным или отрицательным, а также дробью. когда d отрицательно, он должен возвращать цифры после десятичной точки (он не определен для d = 0, так что в этом случае он возвращает 0). Например:

    const double x = 25.73;
    for (int n = -5; n <= 5; n++)
            cout<<digit(x,10,n)<<' ';

должен напечатать: 0 0 0 3 7 0 5 2 0 0 0

Функция должна использовать только циклы, if, exp, pow, log, floor и ceil. то есть без трюков sprintf и т. д.

Спасибо!!!

РЕДАКТИРОВАТЬ: для простоты предположим, что 2 ‹= b‹ = 10

РЕДАКТИРОВАТЬ: также избегайте использования мода, только решения на основе pow-exp-log-floor-ceil


person Troy McClure    schedule 02.01.2013    source источник
comment
Записывать конкретную цифру в double, вероятно, не очень хорошая идея, поскольку представление double не совсем арифметическое десятичной запятой, это арифметика с плавающей запятой. Например, 1.1 может быть представлен как 1.099999999999 или 1.10000000001 (здесь только примеры, а не реальные случаи).   -  person amit    schedule 02.01.2013
comment
(он недооценен для d = 0, поэтому скажем, что он возвращает 0 для d = 0) ПОЧЕМУ?   -  person Cheers and hth. - Alf    schedule 02.01.2013
comment
каково значение b в приведенном выше примере?   -  person Aravind    schedule 02.01.2013
comment
амит: ты определенно прав. Мне это нужно, чтобы проделать более широкий трюк. Приветствия: хорошо, он должен напечатать '.' где d = 0. обратите внимание, что это расположение десятичной точки. Аравинд: это 10, исправлю q спасибо всем!   -  person Troy McClure    schedule 02.01.2013
comment
Что такое расширение числа x по основанию b?   -  person selbie    schedule 02.01.2013
comment
база подсчета, например, b = 2 для двоичного, b = 10 для десятичного и т. д.   -  person Troy McClure    schedule 02.01.2013
comment
относительно хорошо, поэтому он должен напечатать '.' где d = 0., как получить double результат функции для печати как.? мне кажется, эти требования не могли быть частью исходного текста задания. почему бы не воспроизвести этот текст здесь буквально (или со ссылкой, если он общедоступен).   -  person Cheers and hth. - Alf    schedule 02.01.2013
comment
кстати, в чем вопрос   -  person Cheers and hth. - Alf    schedule 02.01.2013
comment
аплодисменты: именно поэтому я сказал «0», а не «.». Итак, у нас есть первая строка: if (d == 0) return 0 ;. теперь вопрос, как писать следующие строчки :)   -  person Troy McClure    schedule 02.01.2013
comment
Если вы можете использовать циклы, но не можете использовать мод, можно ли многократно вычитать базу для воссоздания мода? Есть ли какие-то другие искусственные ограничения, о которых вы не упоминаете, пока кто-нибудь не ответит? В чем вопрос?   -  person Useless    schedule 02.01.2013


Ответы (2)


Это кажется наиболее простой реализацией, и, похоже, она работает нормально.

int digit( double x, int base, int index ) {
    // shift number (mult by power of base) so desired digit is in one's place
    x = std::abs( x ) * std::pow( base, - index );
    // fmod strips higher digits; floor strips lower digits, leaving result.
    return std::floor( std::fmod( x, base ) );
}

Я изменил тип возвращаемого значения с double на int, поскольку нет смысла указывать дробную часть в цифре. И он не возвращает . для 0, потому что это опять же не цифра. Значение 0-го места - это единица.

Также игнорируется знак минус; вы не определили «расширение base-b» для отрицательных чисел. Вы можете настроить функцию так, чтобы она возвращала нотацию дополнения b или что-то еще.

Подставив x, вы можете превратить это в одну строку, так что это будет удовлетворять требованиям для constexpr на платформах, где математические функции также constexpr.

person Potatoswatter    schedule 02.01.2013
comment
это выглядит чудесно. не могли бы вы придумать способ избежать мода? - person Troy McClure; 02.01.2013
comment
@TroyMcClure: Нет. Это не было частью вашего вопроса, и это совершенно необоснованно. Эх, вы могли бы избежать mod, разделив на следующую большую степень base, округляя умножение и вычитание. Фу, теперь мой мозг болит. - person Potatoswatter; 02.01.2013
comment
Можете ли вы взять пример и объяснить, пожалуйста? Я действительно хочу знать, как это работает, выглядит довольно аккуратно. Например, что происходит, когда мы вызываем: cout ‹< digit (3.4562,2,3); Спасибо. - person Aravind; 02.01.2013
comment
@Aravind Попробуйте и убедитесь - вы можете просмотреть примеры в отладчике (или создать его для печати промежуточных значений) быстрее, чем вводить их в браузере и ждать, пока мы вам ответим. - person Useless; 02.01.2013
comment
@Aravind Я добавил комментарии, это поможет? - person Potatoswatter; 02.01.2013
comment
@Potatoswatter: миллион спасибо, я проверю и дам вам знать - person Troy McClure; 02.01.2013
comment
@Potatoswatter: это прекрасно работает. также со следующим: double mymod (double x, int n) {return x-floor (x / n) * n; } - person Troy McClure; 02.01.2013
comment
@TroyMcClure Не возражаете, если я спрошу, для чего это? Если у вас нет fmod, это говорит о том, что вы используете очень ограниченную систему. - person Potatoswatter; 02.01.2013
comment
Моя главная причина в этом вопросе - математическое понимание. это не для целей программирования, но мне нужно математически написать это очень точно, поэтому я проверяю это с помощью простых программ - person Troy McClure; 02.01.2013

Сделаем это в два этапа.

1. преобразовать число в основание b

2. Найдите d-ю цифру и верните ее.

Причина разделения задач заключается в том, что если вы неоднократно вызываете один и тот же набор базы и числа и только для разных d, то мы можем кэшировать число в новой базе. Например, следующая функция преобразует число a от основания 10 до основания b. Мне любопытно, как работать с дробями.

string changeBase(int a,int b)
{
  string A="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  string res="";
  while(a>=b)
  {
      res=A[a%b]+res;
      a=a/b;
  }
  return res;
 }

Нам нужно вернуть в виде строки, так как новая база может иметь цифры, такие как «A», «B» или подобные, которые представляют остатки от 10, 11 и так далее. Затем мы можем поиграть с возвращенной строкой, как показано ниже:

 string A=changeBase(24,2);
 cout<<A[0];//for some d

Для отрицательной поддержки вы можете использовать строковый индекс соответственно в зависимости от того, как вы определяете его для отрицательного d.

person Aravind    schedule 02.01.2013
comment
Это красный флаг, что ваша реализация имеет другое количество аргументов, чем его прототип ... - person Potatoswatter; 02.01.2013
comment
Я только пытался помочь, я не знаю, как бороться с двойными, о которых я упомянул в своем ответе, пожалуйста, прочтите полностью. Спасибо за ваш комментарий. Расскажите, пожалуйста, как я могу преобразовать двойные в другие базы, я могу » Не следуйте своему коду. Не можете ли объяснить? - person Aravind; 02.01.2013
comment
double - это базовый тип, в котором хранятся дроби (числа с плавающей запятой), а также целые числа. Числа не принадлежат определенной базе, когда ими манипулируют с помощью математических операций. Базовая нотация - это то, что люди используют при написании чисел, но нет необходимости преобразовывать число, хранящееся как int или double, из базы 10. - person Potatoswatter; 02.01.2013