На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! правила раздела Алгоритмы
1. Помните, что название темы должно хоть как-то отражать ее содержимое (не создавайте темы с заголовком ПОМОГИТЕ, HELP и т.д.). Злоупотребление заглавными буквами в заголовках тем ЗАПРЕЩЕНО.
2. При создании темы постарайтесь, как можно более точно описать проблему, а не ограничиваться общими понятиями и определениями.
3. Приводимые фрагменты исходного кода старайтесь выделять тегами code.../code
4. Помните, чем подробнее Вы опишете свою проблему, тем быстрее получите вразумительный совет
5. Запрещено поднимать неактуальные темы (ПРИМЕР: запрещено отвечать на вопрос из серии "срочно надо", заданный в 2003 году)
6. И не забывайте о кнопочках TRANSLIT и РУССКАЯ КЛАВИАТУРА, если не можете писать в русской раскладке :)
Модераторы: Akina, shadeofgray
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> Степени нуля
    Не пойму, что вы спорите. Любое число в нулевой степени равно 1 – это пошло как следствие из формулы частного степеней с одинаковым основанием: x0 = xa-a = xa/xa = 1. И как ни странно, строго она легко доказывается через пределы. Т.к. 00 по факту ведёт к неопределённости 0/0, то NaN, и дело с концом.

    P.S. Кому как не тебе, Jin X, знать, что делает FPU с неопределённым результатом, если ему замаскировать #IA и если не маскировать.
    Сообщение отредактировано: Qraizer -
      Цитата Jin X @
      Правильно ли я пишу:
      В целом правильно. Ты повторил то, что я выше написал. Но не рассмотрел некоторых ситуаций.
      Так, основание может стремиться к нулю быстрее показателя, тогда предел сойдётся к нулю, а не к единице.
      Подобрав пару функций, можно добиться предела, равного любому числу от 0 до ∞.

      Цитата Jin X @
      Можно сделать с флагом и 2 обёртки: которая ругается на 00 и которая хавает.
      Более того, можно сделать не флаг, а код корректности:
      Оба варианта не комильфо,
      Установка флага, и потом проверка его в обёртке - это всё-таки лишние телодвижения, причём не являющиеся необходимыми, в то время как две отдельно реализованные функции (возможно с общей вычислительной частью) обойдутся у\куда дешевле. И это не будет преждевременной оптимизацией, при написании библиотек действуют несколько другие правила разработки.
      Так в математических библиотеках как правило есть функции log(x) и log10(x), а часто ещё и log2(x) и log(x, b), хотя казалось бы хватило и одной из них. Просто набор из таких функций можно реализовать эффективнее, чем одну универсальную функцию. И программы от этого становятся несколько читабельнее.
      Код корректности здесь не годится по той же причине, если тебе надо как-то выделить случай X,Y=0, то гораздо читабельнее непосредственно проверить эти значения, чем после вызова функции (!) анализировать какой-то флаг. Не забывай, функцию ты вызываешь внутри какого-то выражения, от того, что ты каждую функцию будешь вызывать по отдельности, и что-то анализировать программа просто перестанет читаться. Или тебе придётся каждый раз писать для неё обёртку, анализирующую этот код завершения. кончится тем, что ты эту обёртку будешть втыкать во все проекты и забудешь про библиотечную функцию с таким нелепым интерфейсом. Код завершения уместен при вызове процедуры, реализующих какой-либо сложный алгоритм, или при вызове функции-фабрики (это я про fopen из C), которые и так обычно вызываются отдельно. И то, в последнем варианте j,sxyj возвращают значение, что что-то пошло не так, а ошибку фиксируют другим способом.

      Добавлено
      Qraizer, большинство математических библиотек возвращают в этом случае всё-же 1, потому как должны работать и с не IEEE-представлениями чисел с плавающей точкой, в которых нет NaN или ±inf.
        Цитата amk @
        log(x) и log10(x), а часто ещё и log2(x) и log(x, b)
        Это оправдано, ибо Ln, Lg и Log2 – очень примитивные функции и отличаются 1 инструкцией (из 2-3-х), которая и определяет основание логарифма.
        Здесь же обёртки очень простые (и они могут быть inline-овыми), а основная функция с кодом результата – это и есть "общая вычислительная часть", которая в сравнении с логарифмами довольно громоздкая.
        А так вообще, конечно, можно подумать на предмет усложнения и упрощения... ибо я не очень уверен, что разделение результата вычисления в зависимости от знака нуля вообще нужнО.

        Цитата amk @
        Не забывай, функцию ты вызываешь внутри какого-то выражения, от того, что ты каждую функцию будешь вызывать по отдельности, и что-то анализировать программа просто перестанет читаться.
        Здесь всё зависит от задачи. Одно дело, когда это функция внутри сложного выражения, другое, когда она, например, внутри калькулятора (анализатора текстовой формулы), где можно играться с этим кодом без проблем.
        Вообще, задумка такая:
        ExpandedWrap disabled
          unit Power7x;
           
          interface
           
          var
            PowerNormalResultLevel: Integer = 1;  // Допустимый уровень результата, возвращаемый функциями FastPower (без параметра Correct), выше которого генерируется исключение
           
          const
            // Коды корректности результата вычисления степени функцией FastPower
            fprOK = 0;    // Корректный результат
            fpr00 = 1;    // 0 в степени 0, результат = 1 (если вы хотите, чтобы результат был не определён, проверяйте этот код либо установите PowerNormalResultLevel = 0 и используйте FastPower без параметра Correct) :)
            fpr0Neg = 2;  // 0 в отрицательной степени, результат = бесконечности (Inf)
            fprInf = 3;   // Слишком большой по модулю результат (бесконечность, +/-Inf)
            fprNaN = 4;   // Попытка возвести отрицательное число в нецелую степень, либо X или Y = NaN, результат - нечисло (QNaN)
           
          // Возведение X в степень Y
          // Возвращает результат возведения в степень, а в переменную Correct записывается код корректности результата (см. fprXXX)
          function FastPower(const X, Y: Single; out Correct: Integer): Single; overload;
          function FastPower(const X, Y: Double; out Correct: Integer): Double; overload;
          function FastPower(const X, Y: Extended; out Correct: Integer): Extended; overload;
           
          // Возведение X в степень Y
          // Возвращает результат возведения в степень, осуществляет проверку корректности результата и генерирует исключение, если результат превышает значение переменной PowerNormalResultLevel
          function FastPower(const X, Y: Single): Single; overload;
          function FastPower(const X, Y: Double): Double; overload;
          function FastPower(const X, Y: Extended): Extended; overload;
           
          // Возведение X в степень Y
          // Возвращает результат возведения в степень, осуществляет проверку корректности результата и генерирует исключение, если результат превышает значение переменной ResultLevel
          function FastPowerChk(const X, Y: Single; ResultLevel: Integer): Single; overload;
          function FastPowerChk(const X, Y: Double; ResultLevel: Integer): Double; overload;
          function FastPowerChk(const X, Y: Extended; ResultLevel: Integer): Extended; overload;
           
          // Возведение X в степень Y
          // Возвращает код корректности результата, а результат возведения в степень записывает в переменную Z
          function FastPowerCode(const X, Y: Single; out Z: Single): Integer; overload;
          function FastPowerCode(const X, Y: Double; out Z: Double): Integer; overload;
          function FastPowerCode(const X, Y: Extended; out Z: Extended): Integer; overload;
           
          // Проверка числа на корректность (возвращает False, если число является Inf или NaN)
          function IsNormal(const X: Single): Boolean; overload;
          function IsNormal(const X: Double): Boolean; overload;
          function IsNormal(const X: Extended): Boolean; overload;
           
          implementation
           
          end.

        Уверен, можно улучшить (т.к. не шибко долго думал над тем, как это лучше сделать), но пока так...

        Добавлено
        Чем мне не нравится Power от Delphi (Math.pas)?
        Как минимум из-за того, что если X < 0, а Y целый и > MaxInt, то он почему-то думает, что Y нецелый...
        Да и к тому же, свой число asm-овский вариант хочу сделать... У меня уже даже есть код, но вот надо решить вопрос с этим нулём.

        Добавлено
        Представьте себе, этот косяк присутствует и в D7, и в Tokyo.
        Ну и можно кое-какие другие моменты соптимизировать... в частности обойтись без очень медленной sahf.
        Это всё 32 бита...
        А вот с 64 битами, конечно, посложнее :)

        Добавлено
        Тут, конечно, с генерацией исключений надо подумать... потому что есть уже настроенный вариант (маска исключений), который трогать нет смысла.
        В общем, я подумаю, как сделать, чтобы не было такого большого кол-ва функций, лишних обёрток с искусственной генерацией исключений и пр.

        Добавлено
        Наверное, amk прав. Лучше сделать 2 функции... но флаг корректности всё равно нужен, чтобы в случае замаскированных исключений можно было проверить результат...
        В ассемблере с этим удобнее, конечно: можно возвращать результат и в st(0), и в AL (сразу)... или во флаг CF, скажем :)
          Цитата amk @
          Qraizer, большинство математических библиотек возвращают в этом случае всё-же 1, потому как должны работать и с не IEEE-представлениями чисел с плавающей точкой, в которых нет NaN или ±inf.
          Не-а, не поэтому. Ты назвал настоящую причину: lim xx при x→0 сходится к 1. Но коли ты упомянул IEEE, то тем более не понимаю, зачем пытаться оспаривать стандарт. Он основан на строгих матִͺправилах.
          Другое дело, что Jin X-у захотелось универсализировать свою функцию. Ну так так бы и сказал, зачем было так странно формулировать вопрос темы.
          Цитата Jin X @
          Вообще, задумка такая:
          ...
          Ужас. Жирный интерфейс у такой простой задачи. У Дельфей вроде есть шаблоны. На них понятие политики поведения можно реализовать?
          Сообщение отредактировано: Qraizer -
            Qraizer, мне захотелось её сделать правильной, в первую очередь. Ну и даль возможность по-разному реагировать на "особые случаи"...

            Добавлено
            Цитата Qraizer @
            Жирный интерфейс у такой простой задачи. У Дельфей вроде есть шаблоны. На них понятие политики поведения можно реализовать?
            Я согласен, что жирный, упрощу.
            Шаблоны работают только для классов, да и появились они в D2009 (вместе с Unicode по дефолту), а людей, пользующихся D7 или D2007 довольно много. К тому же, для Single/Double/Extended это всё не подойдёт, т.к. там должна идти работа с экспонентной частью, которая своя у каждого типа...
              Вот так, думаю, будет нормально...
              Да, тоже много всего, но основных функций всего 3 (+2 перегруженные).
              IsNormal, FloatValueType и FloatValueTypeEx – уже не относящиеся к степени функции, чисто вспомогательные.
              ExpandedWrap disabled
                unit Power7x;
                 
                {$IF CompilerVersion >= 17} // Delphi 2005+
                  {$DEFINE INLINE}
                {$IFEND}
                 
                interface
                 
                const
                  // Коды корректности результата вычисления степени функцией FastPowerNX
                  fprOK = 0;    // Корректный результат
                  fpr00 = 1;    // 0 в степени 0, результат = 1 (если вы хотите, чтобы результат был не определён, проверяйте этот код) :)
                  fpr0Neg = 2;  // 0 в отрицательной степени, результат = бесконечности
                  fprInf = 3;   // Слишком большой по модулю результат (бесконечность)
                  fprNaN = 4;   // Попытка возвести отрицательное число в нецелую степень, либо X или Y = NaN, результат - нечисло (NaN)
                 
                type
                  // Тип значения вещественного числа (нормальное, бесконечность, нечисло)
                  TFloatValueType = (fvNormal, fvInfinity, fvNaN);
                  // Расширенный тип значения вещественного числа (нормализованное положительное и отрицательное, денормализованное
                  // положительное и отрицательное, ноль и отрицательный ноль, плюс и минус бесконечность, нечисло QNaN и SNaN)
                  TFloatValueTypeEx = (fvxPosNormal, fvxNegNormal, fvxPosDenormal, fvxNegDenormal, fvxZero, fvxNegZero, fvxPosInfinity, fvxNegInfinity, fvxQNaN, fvxSNaN);
                 
                  // Тип функции возведения в степень (FastPower или FastPower0N)
                  TFastPowerFunc = function(const X, Y: Extended): Extended;
                  // Тип функции быстрого возведения в целую степень (FastIntPower или FastIntPower0N)
                  TFastIntPowerFunc = function(const X: Extended; Y: Integer): Extended;
                 
                ///////////////////////////////////////////
                // ОСНОВНЫЕ ФУНКЦИИ ВОЗВЕДЕНИЯ В СТЕПЕНЬ //
                ///////////////////////////////////////////
                 
                // Возведение X в степень Y (0^0 возвращает как 1)
                function FastPower(const X, Y: Extended): Extended;
                 
                // Возведение X в степень Y (0^0 возвращает как NaN)
                function FastPower0N(const X, Y: Extended): Extended;
                 
                // Если вам необходимо использовать функцию FastPower или FastPowerN0 в зависимости от ситуации (например, согласно настройкам),
                // вы можете присвоить указатель на одну из этих функций переменной FastPowerFunc и использовать её вместо этих функции.
                var FastPowerFunc: TFastPowerFunc = FastPower;
                 
                // Возведение X в степень Y (0^0 возвращает как 1)
                // Предотвращает генерацию исключений, возвращая код корректности результата в переменную Correct (см. fprXXX)
                function FastPowerNX(const X, Y: Single; out Correct: Integer): Single; overload;
                function FastPowerNX(const X, Y: Double; out Correct: Integer): Double; overload;
                function FastPowerNX(const X, Y: Extended; out Correct: Integer): Extended; overload;
                 
                ////////////////////////////////////////////////
                // БЫСТРЫЕ ФУНКЦИИ ВОЗВЕДЕНИЯ В ЦЕЛУЮ СТЕПЕНЬ //
                ////////////////////////////////////////////////
                 
                // Быстрое возведение X в целую степень Y (0^0 возвращает как 1)
                function FastIntPower(const X: Extended; Y: Integer): Extended;
                 
                // Быстрое возведение X в целую степень Y (0^0 возвращает как NaN)
                function FastIntPower0N(const X: Extended; Y: Integer): Extended;
                 
                // Если вам необходимо использовать функцию FastIntPower или FastIntPowerN0 в зависимости от ситуации (например, согласно настройкам),
                // вы можете присвоить указатель на одну из этих функций переменной FastIntPowerFunc и использовать её вместо этих функции.
                var FastIntPowerFunc: TFastIntPowerFunc = FastIntPower;
                 
                // Быстрое возведение X в целую степень Y (0^0 возвращает как 1)
                // Предотвращает генерацию исключений, возвращая код корректности результата в переменную Correct (см. fprXXX)
                function FastIntPowerNX(const X: Single; Y: Integer; out Correct: Integer): Single; overload;
                function FastIntPowerNX(const X: Double; Y: Integer; out Correct: Integer): Double; overload;
                function FastIntPowerNX(const X: Extended; Y: Integer; out Correct: Integer): Extended; overload;
                 
                /////////////////////////////
                // ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ //
                /////////////////////////////
                 
                // Проверка числа на корректность (возвращает False, если число = бесконечности или NaN)
                function IsNormal(const X: Single): Boolean; overload;
                function IsNormal(const X: Double): Boolean; overload;
                function IsNormal(const X: Extended): Boolean; overload;
                 
                // Получение типа значения вещественного числа
                function FloatValueType(const X: Single): TFloatValueType; overload;
                function FloatValueType(const X: Double): TFloatValueType; overload;
                function FloatValueType(const X: Extended): TFloatValueType; overload;
                 
                // Получение расширенного типа значения вещественного числа
                function FloatValueTypeEx(const X: Single): TFloatValueTypeEx; overload;
                function FloatValueTypeEx(const X: Double): TFloatValueTypeEx; overload;
                function FloatValueTypeEx(const X: Extended): TFloatValueTypeEx; overload;
                 
                implementation
                 
                end.
                Кстати, неплохо бы, чтобы кто-то у вас вычислял -32-0.2, а то как-то натыкался, что стандартные вываливались с ошибкой...

                Добавлено
                Имелось ввиду: (-32)-1/5
                  Ну, если правильной, то только два варианта: либо нуль рассматривается как бесконечно малое, либо как нуль. В качестве маскированной реакции первое, в качестве сигнализирующей – второе.
                  В C некоторые реализации RTL для этого предусматривают специальную функцию _matherr(), которая вызывается при всех математических ошибках. Пользоваться ею не шибко удобно, но в своё время всех устраивало. Чиста по-паскалевски если, можно предусмотреть callback-функцию, которую можно получить/установить парой get...()/set...() функций из твоего модуля. Кому надо, пусть ставят свой обработчик, и нехай он делает, что им надо. Бросает какое-нибудь исключение, например. Или возвращает некое данное, например то же NaN(). В общем, пусть сами решают, как обработчик писать. Дефолтовый же обработчик пусть обрабатывает ситуацию как маскированную реакцию.

                  P.S.
                  Цитата Jin X @
                  Шаблоны работают только для классов, да и появились они в D2009 (вместе с Unicode по дефолту), а людей, пользующихся D7 или D2007 довольно много. К тому же, для Single/Double/Extended это всё не подойдёт, т.к. там должна идти работа с экспонентной частью, которая своя у каждого типа...
                  Та я не о параметризации типов, я о параметризации поведения. Я уже вспомнил, что шаблоны там простенькие, обычные дженерики, и то не факт, что сопоставимые с дженериками в других языках.
                  Просто на Плюсах можно было бы вынести реакцию на спец.ситуации в отдельный класс и передавать его шаблонным параметром. Написать две/три готовых стратегий поведения прям в твоём модуле, а кому мало, может и свои написать. В принципе, в таком классе достаточно было бы иметь всего один метод, по-разному реализованный в разных стратегиях, а твои Power() могут просто звать этот метод той стратегии, которая им передана и не заморачиваться больше ничем.
                  Получилось бы что-то типа:
                  ExpandedWrap disabled
                    namespace Power
                    {
                     
                    // стратегии
                    template <typename T> struct ReturnOne
                    {
                      static T matherr(T, T) { return static_cast<T>(1); }
                    };
                     
                    template <typename T> struct ReturnNaN
                    {
                      static T matherr(T, T) { return std::numeric_limits<T>::quiet_NaN(); }
                    };
                     
                    template <typename T> struct Throw
                    {
                      static T matherr(T l, T r) { return std::runtime_error(static_cast<std::ostringstream&>(std::ostringstream() << std::dec << "Indefinite result for " << l << " and " << r << " params").str()); }
                    };
                     
                    // функция
                    template <typename T, template <typename> class Err = ReturnOne> T power(T l, T r, Err)
                    {
                      if (/* ... */) return Err<T>::matherr(l, r);
                      /* ... */
                    }
                     
                    }
                  Сообщение отредактировано: Qraizer -
                    Цитата Славян @
                    Имелось ввиду: (-32)-1/5
                    Ответ будет 5.66*i, это комплексные числа.

                    Цитата Qraizer @
                    Чиста по-паскалевски если, можно предусмотреть callback-функцию, которую можно получить/установить парой get...()/set...() функций из твоего модуля. Кому надо, пусть ставят свой обработчик, и нехай он делает, что им надо. Бросает какое-нибудь исключение, например. Или возвращает некое данное, например то же NaN(). В общем, пусть сами решают, как обработчик писать
                    Зачем такой заморочь, когда программист просто может написать обёртку, которая будет вызывать нашу функцию и проверять результат (код корректности), в зависимости от которого делать что надо. Единственное, так будет чуть медленнее, т.к. здесь обёртка будет делать лишний вызов и сравнение, а callback – только в случае. Но это надо ещё одну функцию создавать типа
                    ExpandedWrap disabled
                      type TFastPowerErrorCallback = function(const Value: Extended; Code, Tag: Integer);
                      function FastPowerECB(const X, Y: Extended; ErrorCallback: TFastPowerErrorCallback; Tag: Integer = 0): Extended;
                    Если реальный смысл делать это?

                    Цитата Qraizer @
                    Получилось бы что-то типа:
                    К сожалению, C++ знаю плохо, не понимаю фишки :(

                    Добавлено
                    Вот так:
                    ExpandedWrap disabled
                      type
                        // Тип callback-функции для функций FastPowerECB и FastIntPowerECB, вызывается в случае возникновения ошибки/неоднозначной ситуации
                        // Value - результат, который вернула бы функция FastPowerNX, Code - код корректности результата, Tag - пользовательское значение
                        // Не сравнивайте значение Value с каким-либо другим, т.к. значение Inf или NaN вызовет исключение (при стадартных настройках со-процессора в Delphi),
                        // используйте для проверки значение Code или функции IsNormal, FloatValueType, FloatValueTypeEx
                        TFastPowerErrorCallback = function(const Value: Extended; Code, Tag: Integer);
                       
                      // Возведение X в степень Y
                      // Предотвращает генерацию исключений; в случае возникновения ошибки/неоднозначной ситуации вызывается функция Callback, результат которой и возвращается
                      function FastPowerECB(const X, Y: Extended; Callback: TFastPowerErrorCallback; Tag: Integer = 0): Extended;
                       
                      // Быстрое возведение X в целую степень Y
                      // Предотвращает генерацию исключений; в случае возникновения ошибки/неоднозначной ситуации вызывается функция Callback, результат которой и возвращается
                      function FastIntPowerECB(const X: Extended; Y: Integer; Callback: TFastPowerErrorCallback; Tag: Integer = 0): Extended;
                      Цитата Jin X @
                      Цитата Славян @
                      Имелось ввиду: (-32)-1/5
                      Ответ будет 5.66*i, это комплексные числа.
                      Эх, а я надеялся всё же увидеть ответ -0,5. :'(
                        Цитата Славян @
                        Эх, а я надеялся всё же увидеть ответ -0,5.
                        Ой, почему-то вычислял (-32)-0.5, а тут (-32)-1/5=0.5i будет.
                        А чтобы получилось -0.5, можно сделать так: -(32-1/5)

                        Если я всё правильно понимаю...
                        Сообщение отредактировано: Jin X -
                          Э, нет! Суть именно в том, чтобы из отрицательного взять отрицательную степень и получить нормальный (вещественный) ответ, а не хитрить.

                          Добавлено
                          Впрочем, можно отмазаться, если -0,2 не представимо точно в FPU (не знаю, не вникал). Но всё равно, подобрать когда всё представимо, думаю, можно попробовать.
                            Можно сделать так: sqrt(-5)*sqrt(-5) = -5
                              Цитата Jin X @
                              Ответ будет 5.66*i, это комплексные числа.

                              :blink: откуда комплексные числа?

                              ответ будет = 1/(корень 5 степени из -32) = -0,5

                              Добавлено
                              сорри, уже насчитали)))
                                Цитата JoeUser @
                                ответ будет = 1/(корень 5 степени из -32) = -0,5
                                Ты про что? Ответ какого выражения?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0585 ]   [ 16 queries used ]   [ Generated: 18.04.24, 12:53 GMT ]