Сколько цифр в этой основе?

Небольшая поправка к исходному ответу - при удалении также создается значительное количество повторов (так как отмена сама защищена повторами). Это видно из вывода autotrace:

SQL> delete from t1;

10918 rows deleted.

Elapsed: 00:00:00.58

Execution Plan
----------------------------------------------------------
   0      DELETE STATEMENT Optimizer=FIRST_ROWS (Cost=43 Card=1)
   1    0   DELETE OF 'T1'
   2    1     TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=43 Card=1)




Statistics
----------------------------------------------------------
         30  recursive calls
      12118  db block gets
        213  consistent gets
        142  physical reads
    3975328  redo size
        441  bytes sent via SQL*Net to client
        537  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
      10918  rows processed
7
задан whacko__Cracko 5 December 2009 в 06:28
поделиться

13 ответов

В настройках вашего компилятора есть быстрые операции с плавающей запятой. Вам нужны точные операции с плавающей запятой. Дело в том, что log10 (8) / log10 (2) всегда равно 3 по математике. Но, возможно, ваш результат равен 2,99999, например. Это плохо. Необходимо добавить небольшую добавку, но не 0,5. Оно должно быть около 0,00001 или что-то в этом роде.

Почти верная формула:

int size = static_cast<int>((log10((double)num) / log10((double)base)) + 1.00000001);

Действительно верное решение

Вы должны проверить результат своей формулы. Сложность составляет O (log log n) или O (log result) !

int fast_power(int base, int s)
{
    int res = 1;
    while (s) {
        if (s%2) {
            res*=base;
            s--;
        } else {
            s/=2;
            base*=base;
        }
    }
    return res;
}

int digits_size(int n, int base)
{
    int s = int(log10(1.0*n)/log10(1.0*base)) + 1;
    return fast_power(base, s) > n ? s : s+1;
}

Эта проверка лучше, чем проверка грубой силы с базовыми умножениями.

8
ответ дан 6 December 2019 в 06:36
поделиться

Вот решение в bash:

% digits() { echo $1 $2  opq | dc | sed 's/ .//g;s/.//' | wc -c; }


% digits 10000000000 42
7
0
ответ дан 6 December 2019 в 06:36
поделиться

Я думаю, что единственный способ устранить ошибку округления без возникновения других ошибок - это использовать или реализовать целочисленные логарифмы.

0
ответ дан 6 December 2019 в 06:36
поделиться

Проблемы с округлением с плавающей запятой.

log10(216) / log10(6) =  2.9999999999999996

Но вы не можете добавить 0,5, как предлагается, потому что это не сработает для следующих

log10(1295) = log10(6) = 3.9995691928566091   //    5, 5, 5, 5
log10(1296) = log10(6) = 4.0                  // 1, 0, 0, 0, 0

Возможно, использование функции log (значение, основание) позволит избежать этих ошибки округления.

0
ответ дан 6 December 2019 в 06:36
поделиться

Похоже, формула мне подходит:

Number 8 in  base 2 : 1,0,0,0
Number of digits: 4
Formula returned: 3

log10(8) = 0.903089
log10(2) = 0.301029

Division => 3

+1 => 4

Так что это определенно просто ошибка округления.

0
ответ дан 6 December 2019 в 06:36
поделиться

Может быть полезно включить функцию округления (например, + 0,5) в ваш код где-нибудь: вполне вероятно, что деление дает (например) 2,99989787, к которому добавляется 1,0, что дает 3,99989787 и когда это преобразовывается в int , это дает 3.

0
ответ дан 6 December 2019 в 06:36
поделиться
static int numInBase(int num, int theBase)
{
   if(num == 0) return 0;
   if (num == theBase) return 1;
   return 1 + numInBase(num/theBase,theBase);
}
0
ответ дан 6 December 2019 в 06:36
поделиться

Как отмечали другие, у вас есть ошибка округления, но предлагаемые решения просто перемещают опасную зону или делают ее меньше, они не устраняют ее. Если ваши числа являются целыми числами, вы можете проверить - с помощью целочисленной арифметики - что одна степень основания меньше или равна вашему числу, а следующая - над ним (первая степень - это число цифр). Но если вы используете арифметику с плавающей запятой где-либо в цепочке, вы будете уязвимы для ошибок (если ваша база не является степенью двойки, а может быть, даже тогда).

РЕДАКТИРОВАТЬ:
Вот грубое, но эффективное решение в целочисленных арифметика. Если ваши целочисленные классы могут содержать числа размером с основание * число, это даст правильный ответ.

  size = 0, k = 1;
  while(k<=num)
    {
      k *= base;
      size += 1;
    }
1
ответ дан 6 December 2019 в 06:36
поделиться

Вам нужен потолок (= наименьшее целое число, не большее чем) log b (n + 1), а не то, что вы вычисляете прямо сейчас, floor (1 + log b (n)).

Вы можете попробовать:

int digits = (int) ceil( log((double)(n+1)) / log((double)base) );
2
ответ дан 6 December 2019 в 06:36
поделиться

Поскольку ваша формула верна (я только что попробовал), я думаю, что это ошибка округления в вашем делении, из-за которой число будет чуть меньше целого числа, которым оно должно быть. Поэтому, когда вы выполняете усечение до целого числа, вы теряете 1. Попробуйте добавить к окончательному значению дополнительные 0,5 (так что усечение будет фактически круглой операцией).

3
ответ дан 6 December 2019 в 06:36
поделиться

Подойдет любой из следующих вариантов:

>>> from math import *
>>> def digits(n, b=10):
...     return int(1 + floor(log(n, b))) if n else 1
...
>>> def digits(n, b=10):
...     return int(ceil(log(n + 1, b))) if n else 1
... 

Первая версия описана на mathpath.org . Во второй версии + 1 необходимо, чтобы дать правильный ответ для любого числа n , которое является наименьшим числом с d цифрами в базе b. . То есть те числа, которые записываются 10 ... 0 в базе b . Обратите внимание, что ввод 0 должен рассматриваться как особый случай.

Десятичные примеры:

>>> digits(1)
1
>>> digits(9)
1
>>> digits(10)
2
>>> digits(99)
2
>>> digits(100)
3

Двоичный:

>>> digits(1, 2)
1
>>> digits(2, 2)
2
>>> digits(3, 2)
2
>>> digits(4, 2)
3
>>> digits(1027, 2)
11

Изменить : OP утверждает, что решение log может не работать для больших входов. Я не знаю об этом, но если это так, следующий код не должен нарушаться, потому что он использует только целочисленную арифметику (на этот раз на C):

unsigned int 
digits(unsigned long long n, unsigned long long b)
{
  unsigned int d = 0;
  while (d++, n /= b);
  return d;
}

Этот код, вероятно, будет менее эффективным. И да , это было написано для максимальной точки неизвестности. Он просто использует наблюдение, что каждое число имеет по крайней мере одну цифру, и что каждое деление на b , которое не дает 0 , подразумевает наличие дополнительной цифры. Более читаемая версия выглядит так:

unsigned int 
digits(unsigned long long n, unsigned long long b)
{
  unsigned int d = 1;
  while (n /= b) {
    d++;
  }
  return d;
}
7
ответ дан 6 December 2019 в 06:36
поделиться

Используя вашу формулу,

log(8)/log(2) + 1 = 4

проблема заключается в точности вычисления логарифма. Использование

ceil(log(n+1)/log(b)) 

должно решить эту проблему. Это не совсем то же самое, что

ceil(log(n)/log(b)) 

, потому что это дает ответ 3 для n = 8 b = 2, и не то же самое, что и

log(n+1)/log(b) + 1

, потому что это дает ответ 4 для n = 7 b = 2 (при вычислении до полной точности).

На самом деле я получаю любопытные результаты реализации и компиляции первой формы с помощью g ++:

double n = double(atoi(argv[1]));
double b = double(atoi(argv[2]));
int i = int(std::log(n)/std::log(b) + 1.0);

терпит неудачу (IE дает ответ 3), а

double v = std::log(n)/std::log(b) + 1.0;
int i = int(v);

успешен (дает ответ 4). Глядя на это еще раз, я думаю, что третья форма

ceil(log(n+0.5)/log(b)) 

была бы более стабильной, потому что она позволяет избежать «критического» случая, когда n (или n + 1 для второй формы) является целой степенью b (для целых значений n ).

1
ответ дан 6 December 2019 в 06:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: