Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Задачка из области математики. / 9 сообщений из 9, страница 1 из 1
14.03.2017, 15:43
    #39419016
mikron
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
Есть вещественное число R, которое представлено в переменной типа double (IEEE 754)
Нужно найти наибольшую десятичную мантису, которая удовлетворяет условию
R % 10^M = 0 // Делится нацело без остатка.

Другими словами, найти последную ненулевую позицию в десятичном предтсавлении числа.

На примере:
970010.000 -> 1
970000.000 -> 4
970000.001 -> -3

Задача стоит иммено в поиске оптималного решения в плане времени вычислений.
Какие будут соображения?
...
Рейтинг: 0 / 0
14.03.2017, 15:55
    #39419032
Соколинский Борис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
mikron,
1. Переводим в стандартное представление 0.уууExxx.
2. Результат = xxx- количество знаков yyy.
...
Рейтинг: 0 / 0
14.03.2017, 16:02
    #39419039
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
mikronНа примере:
970010.000 -> 1
970000.000 -> 4
970000.001 -> -3
Видишь ли... например, последнее из значений не может быть представлено в виде double по IEEE754 точно таким. Максимально близкое значение - это 0x412D9A200083126F = 970000,001000000047497451305389. Что наводит на мысль, что минус три как бы не очень правильный результат...

Так что если ориентироваться не на значение, а на его представление - то, наверное, наиболее оптимальным будет именно получение строкового представления и обработка полученной строки с целью выявления той самой "точки отсечения".
...
Рейтинг: 0 / 0
14.03.2017, 17:28
    #39419142
mikron
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
Akina,

Это только пример для наглядности.
Пусь для начала число будет точно представимым.
...
Рейтинг: 0 / 0
14.03.2017, 17:41
    #39419150
mikron
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
AkinaТак что если ориентироваться не на значение, а на его представление - то, наверное, наиболее оптимальным будет именно получение строкового представления и обработка полученной строки с целью выявления той самой "точки отсечения".

Я не уверен, что точно представляю себе как работает форматирование / создание строкового / десятичного представления, но в моём представлении для начала придётся вычислить log10(R)
и последователно извлекать значения до достижения остатком опредлённой epsilon.
Можно ли сделать это быстрее?
...
Рейтинг: 0 / 0
14.03.2017, 18:49
    #39419221
д0kХ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
mikronAkinaТак что если ориентироваться не на значение, а на его представление - то, наверное, наиболее оптимальным будет именно получение строкового представления и обработка полученной строки с целью выявления той самой "точки отсечения".

Я не уверен, что точно представляю себе как работает форматирование / создание строкового / десятичного представления, но в моём представлении для начала придётся вычислить log10(R)
и последователно извлекать значения до достижения остатком опредлённой epsilon.
Можно ли сделать это быстрее?

нужно начинать с того , что отрицательная мантиса говорит о том
что число меньше 1 .
и вобще числа нужно приводить к номализованному виду.

но....
математически нормализованный вид x . ]xxx e y
по стандарту IEEE 754 не всегда проходит по точности , там есть свои
заморочки и исключения для чисел с мантисой близкой к 1 .
и для вычислений может использоваться вид xx . [xx e y-1

ваши примеры в нормализованом виде :
970000.001 = 9.70000001 e 5
...
Рейтинг: 0 / 0
14.03.2017, 18:51
    #39419225
д0kХ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
д0kХmikronпропущено...


Я не уверен, что точно представляю себе как работает форматирование / создание строкового / десятичного представления, но в моём представлении для начала придётся вычислить log10(R)
и последователно извлекать значения до достижения остатком опредлённой epsilon.
Можно ли сделать это быстрее?

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

но....
математически нормализованный вид x.xxx e y
по стандарту IEEE 754 не всегда проходит по точности , там есть свои
заморочки и исключения для чисел с мантисой близкой к 1 .
и для вычислений может использоваться вид xx.xx e y-1

ваши примеры в нормализованом виде :
970000.001 = 9.70000001 e 5

прошу прощения ято то я туплю к концу дня , исправился .
...
Рейтинг: 0 / 0
15.03.2017, 05:19
    #39419415
Пётр Седов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
mikronПусь для начала число будет точно представимым.Если округлять не надо, то есть мысль, как это сделать для чисел от 0 до 1. Любая отрицательная степень двойки записывается в десятичной системе счисления так, что количество цифр после точки равно показателю (без минуса). Например, 2 -3 = 0.125, 3 цифры после точки. И так со всеми:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
2 0    = 1
2 -1   = 0.5
2 -2   = 0.25
2 -3   = 0.125
2 -4   = 0.0625
2 -5   = 0.03125
2 -6   = 0.015625
2 -7   = 0.0078125
2 -8   = 0.00390625
2 -9   = 0.001953125
2 -10  = 0.0009765625
2 -11  = 0.00048828125
2 -12  = 0.000244140625
2 -13  = 0.0001220703125
2 -14  = 0.00006103515625
2 -15  = 0.000030517578125
2 -16  = 0.0000152587890625
2 -17  = 0.00000762939453125
2 -18  = 0.000003814697265625
2 -19  = 0.0000019073486328125
2 -20  = 0.00000095367431640625
2 -21  = 0.000000476837158203125
2 -22  = 0.0000002384185791015625
2 -23  = 0.00000011920928955078125
2 -24  = 0.000000059604644775390625
2 -25  = 0.0000000298023223876953125
2 -26  = 0.00000001490116119384765625
2 -27  = 0.000000007450580596923828125
2 -28  = 0.0000000037252902984619140625
2 -29  = 0.00000000186264514923095703125
2 -30  = 0.000000000931322574615478515625
2 -31  = 0.0000000004656612873077392578125
2 -32  = 0.00000000023283064365386962890625
2 -33  = 0.000000000116415321826934814453125
2 -34  = 0.0000000000582076609134674072265625
2 -35  = 0.00000000002910383045673370361328125
2 -36  = 0.000000000014551915228366851806640625
2 -37  = 0.0000000000072759576141834259033203125
2 -38  = 0.00000000000363797880709171295166015625
2 -39  = 0.000000000001818989403545856475830078125
2 -40  = 0.0000000000009094947017729282379150390625
...
Любое double-число от 0 до 1 -- это сумма некоторых отрицательных степеней двойки. Тогда просто ищем самую отрицательную степень двойки в числе, это и даёт нам количество десятичных цифр после точки. Код на C++:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
#include <assert.h>
#include <string.h>

typedef unsigned char byte_t;

enum sign_t {_sign_plus = 0, _sign_minus = 1};

// мантисса (significand) содержит 53 двоичных цифры
const int _significand_len = 53; // = DBL_MANT_DIG из <float.h>

// в таком виде с числом удобно работать
struct unpacked_double_t {
  sign_t sign;
  byte_t significand[_significand_len]; // мантисса
  int exponent; // показатель
};

// double -- в формате IEEE 754 (почти на всех платформах)
unpacked_double_t unpack_double(double x) {
  // получаем битовое представление x
  unsigned long long x_bits;
  memcpy(&x_bits, &x, sizeof(double)); // уважаем strict aliasing

  unpacked_double_t result;

  // распаковываем мантиссу (кроме старшей цифры, она не хранится явно)
  for (int i = 0; i < _significand_len - 1; i++) {
    result.significand[_significand_len - 1 - i] = (x_bits >> i) & 0x1;
  }

  int biased_exponent = (x_bits >> 52) & 0x7ff; // 11 бит
  assert(biased_exponent != 2047); // бесконечности и NAN-ы (not a number) не рассматриваем
  if (biased_exponent > 0) {
    // x -- нормализованное число
    result.significand[0] = 1;
    result.exponent = biased_exponent - 1023;
  } else {
    // x -- денормализованное число (возможно, ноль)
    result.significand[0] = 0;
    result.exponent = 1 - 1023;
  }

  result.sign = static_cast<sign_t>(x_bits >> 63);

  return result;
}

int min_decimal_exponent(double x) {
  assert((0 < x) && (x <= 1));
  unpacked_double_t ux = unpack_double(x);
  // ищем последнюю единицу в мантиссе
  for (int i = _significand_len - 1; ; i--) {
    assert(i >= 0); // хотя бы одна единица должна быть, потому что число ненулевое
    if (ux.significand[i] == 1) {
      return ux.exponent - i;
    }
  }
}

int main() {
  // эти числа точно представимы типом double (в отличие от какого-нибудь 0.1)
  assert(min_decimal_exponent(1) == 0);
  assert(min_decimal_exponent(0.125) == -3); // 2**-3
  assert(min_decimal_exponent(0.1796875) == -7); // 2**-3 + 2**-5 + 2**-6 + 2**-7
  return 0;
}
...
Рейтинг: 0 / 0
15.03.2017, 09:43
    #39419488
mikron
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка из области математики.
Пётр Седов,

Спасибо за детальный ответ. Ваше должно работать для всех вещественнух чисел за исключением натуральных. Таким образом для полного решения необходимо только найти log10(R) целую часть / ограниченнум с низу.
...
Рейтинг: 0 / 0
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Задачка из области математики. / 9 сообщений из 9, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]