Определение.
Однородная функция степени q — числовая функция f : R^n → R такая, что для любого v ∈ R^n из области определения функции f и любого λ ∈ R выполняется равенство: f(λv)=λ^q f(v), где q — называется порядком однородности.
Для простоты берем q=1, и рассматриваем функции вида f(a,b)=(a^117-b^117)^(1/117), f(a,b,c,d)=(a^117-b^117)^(1/117)-(c^117-d^117)^(1/117).
После несложных численных расчетов на Python и Java были получены следующие равенства.
f(352,54)=351.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999...
f(357,59)=356.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998972...
f(361,63)=360.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999939...
MS Excel:
f(352,54)=352,000000000001
f(357,59)=357,000000000001
f(361,63)=361,000000000001
Скрипт на Python:
from decimal import *
getcontext().prec = 308
>>> x=(Decimal(352)**Decimal(117)-Decimal(54)**Decimal(117))(Decimal(1)/Decimal(117))
>>> print(x)
351.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998329159190818894696994980506790444791082984001875203468391468411917936881307214870551679958590777317468915163628481716135549589884152531038661217609555941316588708754835741185821790242245778320061791986803024655
>>> x=(Decimal(357)**Decimal(117)-Decimal(59)**Decimal(117))(Decimal(1)/Decimal(117))
>>> print(x)
356.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999989720158196073692153897626133606380322329055537315843030235571925317558982699264816534943225755076027658785035832219023824960424396774347405335963769219643742987625523407845824626821939913224289857224063032843297400
>>> x=(Decimal(361)**Decimal(117)-Decimal(63)**Decimal(117))(Decimal(1)/Decimal(117))
>>> print(x)
360.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999993921127936674583510825707397891980952152159386267417777344776761307280088078727565211233452220813716097076319749507809649466951661213836906215116123352999333771519212777104493376322107139264556222426180333043207111704
Скрипт на Java аналогичен, единственно, отличие в том, что надо найти библиотеку
для присвоения вида: RESULT=BigDecimalMath.root(POWER,RESULT);
Советую взять библиотеку A Java Math.BigDecimal Implementation of Core Mathematical Functions
MS Excel:
f(398,100,398,308)=7.38964445190504E-13
f(398,100,398,309)=7.38964445190504E-13
Скрипт на Python:
>>> x=(Decimal(398)**Decimal(117)-Decimal(100)Decimal(117))(Decimal(1)/Decimal(117))-(Decimal(398)**Decimal(117)-Decimal(309)Decimal(117))(Decimal(1)/Decimal(117))
>>> print(x)
4.6829537694880400495961208753068636086170585442527635529935481848840914660367426890426968518388082410943344799080628343292984538641902867227063198133880387010206424683985254813925375685020961046102263610649485204384515121661567412189563550051412170861083133399095734629020724759126523504592133E-13
>>> x=(Decimal(398)**Decimal(117)-Decimal(100)Decimal(117))(Decimal(1)/Decimal(117))-(Decimal(398)**Decimal(117)-Decimal(308)Decimal(117))(Decimal(1)/Decimal(117))
>>> print(x)
3.2048787849158093680423522610101807533554641830481900686328630295592641185012838297491718621152607396025746152496522964996997085198842879841026218584337924367377107257472526086034104095639711035849133200650433251604302283626496677147152423702885746810118429098239541285725629711670483877984277E-13
Вычисления на Java дают аналогичный результат.
При этом на OneNote получаем 0.
(398^117−100^117 )^(1/117)−(398^117−308^117 )^(1/117)=0.0
(398^117−100^117 )^(1/117)−(398^117−309^117 )^(1/117)=0.0
Более того, зададим большую точность каждого члена разности в OneNote.
f(398,100,398,309)=(15357461407072152272595341560605217489962580453253454782381000698280555150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728-1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)^(1/117)-(15357461407072152272595341560605217489962580453253454782381000698280554150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728-2114180645468154536609920593038690001743619316845525182583618652336185889082286837642707603829510005111656415448959134686540978425229790947408474334697737411374763474080732609023460376667948921254970853067562089178774007996892973246633386570133532092567215418841778357322933607577932579981669)^(1/117)=0.0
Что делает его использование непригодным даже для элементарных расчетов.
Однако, рассматривай мы данный пример в Access, то получим:
SELECT (15357461407072152272595341560605217489962580453253454782381000698280555150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728 - 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)^(1/117)-(15357461407072152272595341560605217489962580453253454782381000698280554150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728-2114180645468154536609920593038690001743619316845525182583618652336185889082286837642707603829510005111656415448959134686540978425229790947408474334697737411374763474080732609023460376667948921254970853067562089178774007996892973246633386570133532092567215418841778357322933607577932579981669)^(1/117);
или
SELECT (398^117-100^117)^(1/117)-(398^117-309^117)^(1/117);
с одинаковым результатом f(398,100,398,309)=4,54747350886464E-13.
У MS Word не только своя собственная математика, но и свое понимание вычислений.
Делаем таблицу из одного столбца и вычисляем.
15357461407072152272595341560605217489962580453253454782381000698280555150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
A1-A2 = 2,16
15357461407072152272595341560605217489962580453253454782381000698280554150698266871781901372815261064006144084350804830440836948323660592372567223353043470694217100899363125243630508686232896955794063869972410449739272809998037351885263675820458842645745358787039602864806831680779682282811435404889161728
2114180645468154536609920593038690001743619316845525182583618652336185889082286837642707603829510005111656415448959134686540978425229790947408474334697737411374763474080732609023460376667948921254970853067562089178774007996892973246633386570133532092567215418841778357322933607577932579981669
A5-A4=2,14
A3-A6=0,02
Что совсем неверно (а формула A5-A4=2,14, никак и нигде объяснения не находит) .
Резюме такое. Существует множество пар значений однородных функций от двух и четырех переменных, которые вызывают сложности в MS Office 365 Excel, Word, OneNote, но не в Access.
Комментарии (30)
lamerok
31.01.2022 06:55+2После несложных численных расчетов на Python и Java были получены следующие равенства.
f(352,54)=353.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999...
Я может не правильно понял, но как на Python получилось: f(352,54)=353.9. Ведь результат должен быть меньше 352...
117 степень это далеко за пределами эпсилон для long double, поэтому отнимая, от 352^117 -54^117, вы ровным счетом не делаете ничего, если только ваши тулы не умеют работать с оочень большими числами. Скорее всего эксель этого делать не умеет.
OBIEESupport Автор
31.01.2022 08:35-3Я исправил найденную вами опечатку. Я ожидал от Excel прыти Access. Если вам не видно, что он справился с задачей и длиннной арифметикой в рамках double, то прошу посмотреть именно под углом, почему программы MS Office не считают одинаково.
117 степень это далеко за пределами эпсилон для long double
Будем опровергать ваше утвержение через C++? Или поверите, что с Access'ом любой результат этой программы совпадет?
#include <cmath> #include <limits> #include <iomanip> #include <iostream> #include <type_traits> #include <algorithm> template<class T> typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type almost_equal(T x, T y, int ulp) { // the machine epsilon has to be scaled to the magnitude of the values used // and multiplied by the desired precision in ULPs (units in the last place) return std::fabs(x-y) <= std::numeric_limits<T>::epsilon() * std::fabs(x+y) * ulp // unless the result is subnormal || std::fabs(x-y) < std::numeric_limits<T>::min(); } int main() { double d1 = 0.2; double d2 = 1 / std::sqrt(5) / std::sqrt(5); std::cout << std::fixed << std::setprecision(20) << "d1=" << d1 << "\nd2=" << d2 << '\n'; if(d1 == d2) std::cout << "d1 == d2\n"; else std::cout << "d1 != d2\n"; if(almost_equal(d1, d2, 2)) std::cout << "d1 almost equals d2\n"; else std::cout << "d1 does not almost equal d2\n"; }
lamerok
31.01.2022 10:05+2Будем опровергать ваше утвержение через C++?
как можно опровергнуть истину?
std::numeric_limits<T>::epsilon() * std::fabs(x)
Если x = 352^117, epsilon для long double = 1.0842e-19, то для компилятора, все числа в диапазоне что 352^117+- 352^117 * epsilon одинаковые.
И отнимание 54^117, тут никакой роли уже не играют. Это все будет 352^117.
А код то вы верный привели, только цифры там не те. Вы те подставьте.
Tiriet
31.01.2022 10:12+6почему программы MS Office не считают одинаково
Потому что студент, окончивший технический ВУЗ и знакомый хотя-бы с азами вычислительной математики знает, что что порядок выполнения операций на числах с плавающей точкой и точность представления самих чисел влияют на конечный результат. Питон умеет в длинные целые числа. Проверьте свои питонячьи формулы на вот таком примере:
f(352.5,54.5)
f(357.5,59.5)
f(361.5,63.5)
Собственно, вся великолепаная точность Ваших расчетов определяется тем простым фактом, что Вы загнали в свою формулу только целые числа и использовали модуль decimal! Как следствие- расчеты шли в рамках арифметики длинных чисел. Деление целого на длинное целое дало в результате рациональную дробь, которую питон попытался представить максимально точно десятичной дробью, и поэтому в Ваших результатах получилась такая красота. Работали бы с флоатами- все было бы так же, как и в Ёкселе. А корени всей беды в двух вещах- плохое знание математики и незнание документации на модуль Decimal
decimal
— Decimal fixed point and floating point arithmeticSource code: Lib/decimal.py
The
decimal
module provides support for fast correctly-rounded decimal floating point arithmetic. It offers several advantages over thefloat
datatype:Decimal “is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle – computers must provide an arithmetic that works in the same way as the arithmetic that people learn at school.” – excerpt from the decimal arithmetic specification.
Decimal numbers can be represented exactly. In contrast, numbers like
1.1
and2.2
do not have exact representations in binary floating point. End users typically would not expect1.1 + 2.2
to display as3.3000000000000003
as it does with binary floating point.The exactness carries over into arithmetic. In decimal floating point,
0.1 + 0.1 + 0.1 - 0.3
is exactly equal to zero. In binary floating point, the result is5.5511151231257827e-017
. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.
OBIEESupport Автор
31.01.2022 10:17-4Извините, я исследую целые числа.
Tiriet
31.01.2022 11:58+2если бы Вы использовали просто целые числа, но ведь Вы используете в питоне-длинные целые числа, а в офисе- простые целые и простые вещественные. У Вас объект исследования в разных условиях разный!
OBIEESupport Автор
31.01.2022 12:07-2Вас успокоит, если я напишу, что в OpenOffice я могу пристыковать макрос на Питоне и писать значения прямо в ячейки?
Или немного проще - выставляя непомемерную длину я как раз и исследую - нужен ли мне код прямого сопряжения Java c MS Office, или мне остаться на внутренних типах данных - а они там double точность имеют. И еще ряд красивых, но далеких от статьи вопросов.
Tiriet
31.01.2022 12:57+2не совсем понимаю, что значит "код прямого сопряжения", но с практической точки зрения использовать длинную арфиметику не нужно никому и никогда, точности double достаточно для любых жизненных рассчетов. Обычно достаточно даже single, но в научных рассчетах- уже нет. Да, я знаю про расчеты траекторий спутников схемами Рунге-Кутты 24го порядка точности на вещественных числах повышенной разрядности- но примеры такого рода не относятся к "практической точке зрения". А для практики точность double позволяет описать размер видимой Вселенной с точностью в половину диаметра протона.
OBIEESupport Автор
31.01.2022 13:19-1Еще раз пишу, что у меня вполне серьезные расчеты, где double - только первое и очень плохое приближение.
совсем понимаю, что значит "код прямого сопряжения",
--- это означает что внешняя функция на Java будет видна как внутренняя ф-ция Эксель.расчеты траекторий спутников схемами Рунге-Кутты 24го порядка
-- я тоже это видел. И статью поместил, чтобы оценить масштаб проблемы.Tiriet
31.01.2022 13:44+1Заинтриговали. Можно хоть намекнуть- какая у Вас область науки или техники, что не хватает точности fp64?
mayorovp
31.01.2022 10:21+2И что же должен доказать приведённый вами код?
OBIEESupport Автор
31.01.2022 11:23-1Код приведен: для Питона - для контроля значений, для Java - мне понравилась сама библиотека.
Neom1an
31.01.2022 08:56+3Вот мы и выяснили опытным путём, что в офисном пакете бюджет семьи сводить можно, а проектирование космических шаттлов требует специфического по
OBIEESupport Автор
31.01.2022 08:58-4Спасибо, первое положительное слово за время существования статьи ). До ПО специфического и его проблем я еще надеюсь дойти.
Tiriet
31.01.2022 10:16+3Вы сами использовали специфическое ПО- модуль decimal из python - который работает с длинными числами, со всеми вытекающими из этого плюсами (в виде точных вычислений) и минусами- адско низкая скорсть вычислений, так как все они идут, фактически, "в столбик"- как в школе учили, прямо циферка за циферкой, надо представление числа мегабайт памяти- вот мегабайт и выделится, а не 8 байт на все про все и че хочешь делай.
OBIEESupport Автор
31.01.2022 13:13-2Модуль decimal есть в стандарте, кажется, с 2.3 точно. Плюс к этому в 3.3 и 3.6. он модифицировался. И еще, вариантов с такой точностью не так и много. Хоть тушкой, хоть чучелом, но цифры должны считаться. На заре программирования была у меня библиотека на ассемблере из великолепной книжки "Программирование на Паскале для Windows 95". Но лучше все из одной коробки, чем глюки из многих.
Tiriet
31.01.2022 13:36+1Времена Windows 95- это "заря программирования"? у меня отец к тому времени уже на третий или четверый язык программирования переходил.
Но это все никак не отменяет того, что арифметика длинных чисел- это специализированное ПО, заточенное именно под длинные числа, для которых недостаточно ограничений fp64/int64- то есть, их разрядности.
OBIEESupport Автор
31.01.2022 14:04Если считать FoxPro 3 Dos/Win, Dbase2 Dos, Кларион языками программирования, а ассемблер x86, PDP, Фортран II,4,90 за отдельные языки, то это - моя середина. А перфокарточные и ленточные языки я устану перечислять, поэтому я привел книгу, и я - не ваш папа, а, видимо, чуть старше...
Tiriet
31.01.2022 13:41проектирование Шаттлов, кстати, идет на тех же самых fp64, что и бухгалтерия в офисном пакете :-). Я только два раза сталкивался с необходимостью вылезать за их рамки- это упомянутая уже мной астрономическая задача моделирования траекторий спутников с учетом всяких гравитирующих тел- там, емпнип, хватало самописных fp128 и разностных схем очень высокого порядка ( Рунге-Кутты 20 и 24го порядков) и рассчет определителей одних хитрых сильно узко-специальных матриц. А так научные расчеты вполне себе довольствуются реализованной в железе математикой (читай- fp64/int64), и им хватает.
saboteur_kiev
А точно ли дело в каких-то функциях, а не в том, что excel просто не умеет работать с числами такой точности?
там и двух переменных будет достаточно.
OBIEESupport Автор
Технические характеристики и ограничения вычислений
Точность представления чисел, разрядов, не более
15
Допустимое отрицательное число, не менее
-2,2251E+308
Допустимое положительное число, не менее
2,2251E-308
Допустимое положительное число, не более
9,99999999999999E+307
Допустимое отрицательное число, не более
-9,99999999999999E+307
Наибольшее положительное число, получаемое в формуле
1,7976931348623158E+308
P.S. Разные функции и разные примеры. Я за точность не вышел.
MUTbKA98
Сколько разрядов у числа pow(352, 117)?
OBIEESupport Автор
Извините, точность представления и числом разрядов давайте не путать.
Но, если очень хочется, то 8820467963926921130312091500044678368409598586829469645973915907304374764958435011512423559373974654245260675316210428277114150357601927000338714393368081033522500474128287533659250261359818063641671088268295219592690846839399955310330080876870476387873784102799185035389119711894256175063888822272
MUTbKA98
Давайте не путать.
Так сколько ж мантисса у (long)double, сколько у этого числа и почему это важно?
OBIEESupport Автор
8,82046796392692E+297 Мантисса 82046796392692
4,89857655151656E+202 Мантисса 89857655151656
Извлекли из разности корень 117 степени
Получили 3,520000000000010E+02
Вопрос: как извлекая корень из явно уменьшающегося числа мы получаем число большее?
MUTbKA98
А для Вас разница в 95 порядов несущественна?
Подсказка: Попробуйте не вычитать второе число из первого, а просто извлечь нужный корень из первого числа. Результаты сравнить.
OBIEESupport Автор
Да, в моих расчетах
разница в 95 порядов существенна
. Но вы забываете про 117. Я-то не вычту, а Excel опять показывает 3,520000000000010E+02 ---------------- и вот это называется специально подобранная степень. Попробуйте, пожалуйста.Tiriet
Ёксель получил два здоровенных числа, отличающихся в 15-16м знаке, и имеющих множитель порядка 10^20. Вычел одно из другого, и получил разницу вида 0,0(15 штук нулей)0352E+20. Нормализовал ее по правилам IEEE754 и получил конечный результат: 3,52(16 нулей)Е+2. Это называется не "правильно подобранная степень", а "незнание матчасти". В смысле, и математической и материальной части.
OBIEESupport Автор
Но он не должен писать корень больше, чем то число из которого я еще и что-то отнял. Почему вы не проверяете тот же Word?
Tiriet
почему нет? Вы взяли число, и возвели его в очень большую степень. Получили совсем большущее число, которое не влезло в разрядность дабла, пришлось обрезать его в 18м значащей цифре, Теперь пытаемся вычислить корень большущей степени из этого числа. но проблема в том, что у этого корня есть погрешность- в последнем бите, и если этот последний бит равен нулю- то приближенное значение отличается от истинного значения сильнее, чем если в этом бите единичка (потому что рассчет большой степени идет тоже с накоплением ошибки). Оки, процессор (не эксель, а процессор!) ставит в этот бит единичку, и опа- оказывается, что приближенное значение оказалось больше.
398 и 100 отличаются в 4 раза. 398^117 и 100^117 отличаются в в ~4^117 = 2^234. у них сдвиг на 234 бита. а на весь флоат выделено 64. Поэтому Вы ничего не отнимали от 398^117, Вы сначала вычислили Z=X^117 и чуть-чуть загрубили результат (откинув и округлив примерно 100 значащих младших разрядов, и возможно- увеличив при округлении результат в 16-17 цифре!), получив Z' а потом- вычислили корень, максимально близкий к реальному значению корня из Z'. Вот поэтому у Вас и получилось, что Y~= Z'^(1/117) > X=Z^(1/117).