powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Перемена место множителя в выражении имеет значение
13 сообщений из 38, страница 2 из 2
Перемена место множителя в выражении имеет значение
    #39844958
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

ладно, хоть andrey_anonymous и не захотел "делиться своими секретами",
из топика надо как-то разумно выходить, раз уж влез в него.
Решил накидать модель того, что в предыдущем посте было названо "сложением по Кислицкому",
поскольку вряд ли что-то вообще гуглится по такому названию, и вряд ли каждый из прочитавших немедленно понял, о чем идет речь.

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

Альтернативную идею можно сформулировать так:
1) образуй частичные суммы
2) складывай между собой такие частичные суммы, которые испытали до этого одно и то же количество сложений.

Из такой формулировки выводится две несхожие реализации, одна из которых в статье
англоязычной википедии о сложении по Кахану названа попарным сложением,
а другая не упоминается.

Общего между ними то, что в обоих случаях образуется двоичное дерево вычислений одной и той же высоты.
Общее число сложенных элементов определяется как 2 в степени высоты дерева.
Высота 64 достаточна для сложения 2**64 слагаемых, что выглядит как с большим запасом достаточное количество для использования в обычных базах данных (18 446 744 073 709 551 616 слагаемых).
64 - это оценка максимальной глубины рекурсии попарного сложения, построенного на рекурсивном методе "разделяй и властвуй", и это же оценка необходимого количества "ячеек" дополнительной памяти, в которые складываются частичные суммы во втором методе.
То есть использование дополнительного массива в 64 элемента обеспечивает достаточно
места для сложения результатов, определяемых частичными суммами, испытавшими одно и то
же число сложений. этот массив можно назвать "счетчиком сложений", хранящим результаты самих частичных сложений - т.е. простейшими счетами - абаком, в ячейки которого складываются частичные суммы.

В отличие от метода "попарных сумм" такой заход обеспечивает отсутствие рекурсии,
высокую степень локальности хранимых данных, легко приспосабливается к работе в параллельном окружении, и годен для работы с потоковыми данными.
При одной и той же асимптотической производительности и одинаковых
статистических характеристиках нарастания ошибки, он должен несколько быстрее работать именно на массивах, а на потоках попарное сложение ему не конкурент.

Сейчас набросал вариант реализации для binary_double чисел, для которых алгоритмы подомного сорта и предназначены.

Определим на схеме коллекцию числе binary_double:

Код: plsql
1.
Create or replace Type T_TAB_BDOUBLE as table of binary_double;





Работу счетчика сложим в объект:

Код: plsql
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.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
create or replace type t_bdouble_sumcounter as Object (
-- суммирование binary_double на двоичном счетчике-абаке

  a_counter T_TAB_BDOUBLE,
  
  -- конструктор по умолчанию
  constructor function t_bdouble_sumcounter(Self  in out nocopy t_bdouble_sumcounter) return Self as result,

  -- добавление слагаемого в счетчик
  -- pd_amount in Binary_Double - добавляемое слагаемое
  -- p_carry out binary_double - сумма после переполнения старшего разряда, иначе ноль
  member procedure put(Self  in out nocopy t_bdouble_sumcounter, pd_amount in Binary_Double, p_carry out binary_double),    
  -- съем текущей суммы со счетчика
  member function get_sum(Self  in out nocopy t_bdouble_sumcounter) return binary_double
)
/
create or replace type body t_bdouble_sumcounter is 
  
  -- конструктор по умолчанию
  constructor function t_bdouble_sumcounter(Self  in out nocopy t_bdouble_sumcounter) return Self as result
  Is 
     -- размер счетчика
     ci_MaxLen constant pls_integer := 64;
  Begin
    self.a_counter := new T_TAB_BDOUBLE();
    self.a_counter.Extend(ci_MaxLen);
    Return;
  End;

  -- добавление слагаемого в счетчик
  -- pd_amount in Binary_Double - добавляемое слагаемое
  -- p_carry out binary_double - сумма после переполнения старшего разряда, иначе ноль
  member procedure put(Self  in out nocopy t_bdouble_sumcounter, pd_amount in Binary_Double, p_carry out binary_double)
  is
    cdbl_Zero constant binary_double := 0.0D;  
    i pls_integer;
    tmp_sum binary_double;
  Begin
    p_carry := cdbl_Zero;
    If pd_amount is null Then Return; End If;
    
    -- проверка стартового разряда
    i := Self.a_counter.First;
    If Self.a_counter(i) Is Null
      Then
      Self.a_counter(i) := pd_amount;
      Return; -- ранний возврат
    End If;
    -- здесь оказываемся, только когда первый разряд занят значением
    tmp_sum := pd_amount ;
    
    -- складываем и переносим заполненные разряды
    While Self.a_counter(i) is not Null
    Loop
      tmp_sum := tmp_sum + Self.a_counter(i);
      Self.a_counter(i) := Null;
      i := Self.a_counter.Next(i);    
      Exit When i Is Null;
    End Loop;    
    
    If i Is Not Null
      Then -- формируем значение для следующего разряда
        Self.a_counter(i) := tmp_sum;
    Else
      -- переполнение счетчика, формируем p_carry    
      p_carry := tmp_sum;
    End If;
  End;    
  -----------------------------------------------------------------
  -- съем текущей суммы со счетчика
  member function get_sum(Self  in out nocopy t_bdouble_sumcounter) return binary_double
  is    
    cdbl_Zero constant binary_double := 0.0D;     
    i pls_integer;
    dbl_result binary_double;
  Begin
     i := self.a_counter.First;
     
     <<OUTER_L>>
     While i is Not Null
     Loop  
       -- пропуск пустых значений
       While self.a_counter(i) is Null
       Loop         
         i:= self.a_counter.Next(i);
         Exit OUTER_L When i is Null;
       End Loop;    
       -- накопление результата
       dbl_result := Coalesce(dbl_result, cdbl_Zero) + self.a_counter(i);
       i:= self.a_counter.Next(i);
     End Loop;
    Return dbl_result;
  End;  
    
End;
/



Параметр p_carry процедуры put в норме возвращает ноль.
Как только он вернул не ноль, это значит, что разрядной сетки счетчика не хватило
для поддержки высоты вычисления, и с полученным числом вызывающий клиент дальше
должен обходиться самостоятельно - разрядная сетка счетчика переполнилась.

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

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

PS1
Почему использовал название "сложение по Кислицину"

На ютубе как-то набрел на ролики, обсуждающие алгоритм Кислицина поиска наименьшего и следующего за ним наименьшего, упоминаемый в 17 томе УМН 1962г. (Успехи математических наук) в заметках о заседаниях Ленинградского математического общества.
(сам алгоритм в УМН не приводится, но дается асимптотическая оценка его сложности).
Двоичный счетчик существенно используется в том алгоритме, но в более сложном конструктивном исполнении.
Мимоходом при обсуждении в ролике на ютубе сказано, что с такими счетчиками можно делать много полезных вещей, простейшей из которых является сложение чисел с плавающей точкой с хорошими статистическими характеристиками и по скорости нарастания ошибки
и по общей производительности.

Т.е., в своей идее, это уже очень старый алгоритм.
Возможно уже "ненужный" или даже "бесполезный" в контексте обнаружения метода Ноймайера.

За сим из топика выхожу.

PS2
надеюсь, топикстартер не сильно обижен за такое замусоривание его топика.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39844963
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
boobyи вряд ли каждый из прочитавших немедленно понял, о чем идет речь.Прямо тут нужно было остановиться - ибо оно именно так. Вы тут на пару выдумали никому не нужную задачу и извели на неё слишком много букв.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39844978
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
думаю, настоящая задача возникнет, когда заказчик скажет, что ему пофиг все тонкости машинного округления и троичных систем,
и что значение выражения round(0.0725* 2 / 300 * 30900, 2) должно равняться 14,94
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39844985
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxдумаю, настоящая задача возникнет, когда заказчик скажет, что ему пофиг все тонкости машинного округления и троичных систем,Ага, разные военные чмо пытались продавить, что в военное время пи равно, скажем, трём.
Если заказчик дурак, то это не лечится.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845091
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic,

может быть не заметил, но вообще единственным сообщением по теме, в топике был пост от Тролин.
После него в этом топике остается только плясать и веселиться, а ты на людей бросаешься...

На месте Oracle и я бы заявил, что это not a bug - кто же будет менять математику, работавшую столько десятков лет,
да и созданную задолго до формирования подходящих к случаю стандартов.
Воспроизводимость повторного вычисления важнее.

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

для себя когда-то я сваял, как раз по аналогичному случаю, такую функцию:

Код: plsql
1.
2.
3.
4.
Function ROUND2P(pn_value In Number, pd_digits in Number) Return Number deterministic
  is Begin
  Return ROUND(ROUND(pn_value, (pd_digits + 2)), pd_digits);
End; 





я ее не рекламирую, не афиширую и не обсуждаю с кем бы то ни было.
Просто использую в таких местах, за которые меня те, кто знает о существовании числа пи, не смогут укусить.
3, кстати, очень хорошее приближение пи для многих практических случаев, не только в военное время.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845103
iOracleDev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
boobyдля себя когда-то я сваял, как раз по аналогичному случаю, такую функцию:

Код: plsql
1.
2.
3.
4.
Function ROUND2P(pn_value In Number, pd_digits in Number) Return Number deterministic
  is Begin
  Return ROUND(ROUND(pn_value, (pd_digits + 2)), pd_digits);
End; 





А если в периоде не 9 а 6?
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845104
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
iOracleDev,

вы не прочитали - мною функция не обсуждается.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845105
iOracleDev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsevне очень понятно, в чем проблема деления на 3, это всего лишь сдвиг на один разряд вправо в троичной системе счисления
1/2 в троичной системе?
1/3 и 1/2 в одном выражении?
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845293
grinn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день всем.
А почему получается такой результат?
Код: plsql
1.
2.
3.
SELECT 1 ,ROUND(14.935, 2) FROM dual
UNION ALL
SELECT 2 ,ROUND(14.9349, 2) FROM dual;


Код: plsql
1.
2.
1	14,94
2	14,93
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845303
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
grinnА почему получается такой результат?Правила округления, 5й класс средней школы.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845307
grinn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-,
Похоже, прогулял тот урок.
Был уверен, что округлять начинаем с самого младшего разряда.
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845338
Proteus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxдумаю, настоящая задача возникнет, когда заказчик скажет, что ему пофиг все тонкости машинного округления и троичных систем,
и что значение выражения round(0.0725* 2 / 300 * 30900, 2) должно равняться 14,94
В корень зришь, именно это и произошло. Пришлось изменить формулу расчета для того что бы она соответствовала формуле проверки. ( я конечно не понял их идеи о проверке расчета той же формулой но ничего не докажешь )
...
Рейтинг: 0 / 0
Перемена место множителя в выражении имеет значение
    #39845344
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Proteus... ( я конечно не понял их идеи о проверке расчета той же формулой но ничего не докажешь )
ты же в первом посте написал:
Выражение меняет значение при изменении последовательности его вычисления

написанное пером не вырубается топором.
У тебя нет свободы выбора.
У клиента тоже нет.
вопрос лишь в том, чья несвобода напористей.
...
Рейтинг: 0 / 0
13 сообщений из 38, страница 2 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Перемена место множителя в выражении имеет значение
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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