Вычисление математических функций в j2me (exp, ln, log, arcsin, arccos, arctn, power, root)

Вычисление математических функций в j2me (exp, ln, log, arcsin, arccos, arctn, power, root)

Конфигурация CDLC 1.1 позволяет работать с вещественными числами, поддерживая тип double. Однако стандартная библиотека Math включает в себя очень скудный набор математических функций: sin, cos, tan, sqrt. Существует несколько сторонних математических классов (например, Real.java, которую можно скачать по адресу http://sourceforge.net/projects/real-java). В этой статье я предлагаю написать собственную реализацию нескольких популярных математических функций.\r\n\r\nВ основе компьютерной математики лежит использование разложений функций в математические ряды. Подробно этот вопрос рассматривается в курсе Математического анализа любого Вуза. Если вкратце, то математическую функцию можно представить в виде бесконечной суммы слагаемых, причем каждое следующее слагаемое по модулю меньше предыдущего. Поэтому для вычисления функции с заданной точностью нужно выполнять сложение до тех пор, пока следующее слагаемое не станет меньше, чем требуемая точность вычисления.

Вычисление Экспоненты

Из курса математического анализа известно, что экспоненту можно представить в виде бесконечного ряда\r\n\r\n.

При этом, чем больше аргумент x, тем больше слагаемых требуется брать для удовлетворения требуемой точности. При x>706 exp(x) не умещается в переменную типа double, поэтому перед вычислением экспоненты целесообразно проверить значение x на превышение порогового предела. Для реализации эффективного алгоритма вычисления экспоненты, нужно воспользоваться известным из курса школьной алгебры фактом:

Очевидно, число x<706 можно представить в виде суммы:\r\n\r\nгде коэффициенты a могут принимать значения 0 или 1, а b<1.

Величины можно вычислить заранее и записать в массив. Затем вычленить из x целую(b) и дробную часть. Для дробной части вычислить экспоненту как сумму ряда Тейлора. Найти ai можно, переведя целую часть числа x в двоичную систему. Тогда самому правому символу в двоичном представлении числа соответствует a0, второму справа числу – a0, и так далее. Ниже приведен код функции, вычисляющей экспоненту числа:

private double MExp(double x0){ \r\n    double x=x0;\r\n    if (x0<0){x=-x0;} \r\n   //Массив со степенями экспоненты. \r\n   double ExpConst[]={\r\n        2.718281828459045, //e^1\r\n        7.389056098930649, //e^2\r\n        54.59815003314422, //e^4\r\n        2980.957987041726, //e^8\r\n        8886110.520507860, //e^16\r\n        78962960182680.61, //e^32\r\n        6.235149080811582e27, //e^64\r\n        3.887708405994552e55, //e^128\r\n        1.511427665004070e111, //e^256\r\n        2.284413586539655e222 //e^512 \r\n    };\r\n   int x1=(int)x; //Выделяем целую часть числа\r\n   //Вычисляем экспоненту как сумму ряда Тейлора\r\n   int long n=1;\r\n   double b=1;\r\n   double sn=1; \r\n   while (sn>1E-16){\r\n        sn=sn(x-x1)/n;\r\n        b=b+sn;\r\n        n=n++;\r\n   }\r\n   //Переводим показатель экспоненты в двоичную систему.\r\n   StringBuffer s1=new StringBuffer(10);\r\n   s1.append(Integer.toBinaryString(x1)); \r\n   int len=s1.length();\r\n   for (int i=s1.length(); i>0;i--)\r\n   {\r\n       if (s1.charAt(i-1)=='1'){b=bExpConst[len-i];}\r\n   }\r\n    if (x0<0){b=1/b;}\r\n    return b;\r\n}

\r\nГиперболические функции\r\n\r\nИмея функцию для вычисления экспоненты, легко найти значения гиперболических функций.\r\n\r\n, , .\r\n\r\nИмеет смысл предварительно записать значение exp(x) во вспомогательную переменную, которую затем использовать для вычисления по формулам.\r\nВычисление натурального логарифма\r\n\r\nНатуральный логарифм можно представить в виде суммы:\r\n\r\n\r\n\r\nВычислять значение логарифма непосредственно по этой формуле не очень эффективно. Для оптимизации алгоритма вычисления можно воспользоваться известными соотношениями\r\n\r\nПредставим число x в виде\r\n\r\n\r\n\r\nгде b<1, a-целое, тогда\r\n\r\n.\r\n\r\nДля того чтобы представить число x в требуемом виде, нужно найти позицию символа “E” в строковом представлении числа x, тогда a равно числу, записанному правее символа “E” плюс 1, a b – числу записанному левее “E”, деленному на 10.\r\n\r\nНиже представлен код, реализующий алгоритм вычисления натурального логарифма:\r\n\r\n

private double MLn(double x0){\r\n    double x=x0;\r\n    double y=0;\r\n        //Получаем показатель степени.\r\n        String s0=""+x;\r\n        int i=s0.indexOf("E");\r\n        String s1=s0.substring(i+1, s0.length());//Правее E \r\n        String s2=s0.substring(0, i);//Левее E\r\n        double a=0,b=0; \r\n        a=Double.parseDouble(s1)+1;\r\n        b=Double.parseDouble(s2)/10; \r\n  //Вычисление Логарифма b как суммы ряда Тейлора\r\n       int n=1;\r\n       double sn=1;\r\n       while (sn>(1E-16)n){\r\n          sn=-sn(b-1);\r\n          y=y+sn/n;\r\n          n=n++;\r\n      }\r\n    y=y+a2.302585092994046;\r\n    return y;\r\n}\r\n

\r\n\r\nВычисление корней, степеней и логарифмов\r\n\r\nИмея функцию для вычисления натурального логарифма, легко вычислить следующие функции:\r\n\r\n \r\nВычисление арксинуса и арккосинуса\r\n\r\nВычисление обратных тригонометрических функций arcsin и arcos сводится к вычислению рядов.\r\n\r\nНиже приведен алгоритм вычисления арксинуса.\r\n\r\n

private double Marcsin(double x0){\r\n    double x=x0;\r\n    if (x0<0){x=-x0;}\r\n    double y=x;\r\n    int n=1;\r\n    double sn=x; \r\n    while (sn>1E-16){\r\n            sn=sn(2+1.0/n)0.5xx;\r\n            y=y+sn/(2n+1)/(2n+1); \r\n            n=n+1;\r\n    }\r\n    if (x0<0){y=-y;}\r\n    return y; \r\n}\r\n

\r\n\r\nВычисление арктангенса \r\n\r\nПредложенная формула эффективна для вычисления арктангенса малого аргумента. Для построения алгоритма эффективного вычисления арктангенса от больших x, целесообразно воспользоваться формулой:\r\n\r\n\r\nНиже предлагается переписанный для java алгоритма, который написал товарищ Nikitin V.F. в 2000 году.\r\nВначале нужно проверить знак x, если x<0, нужно изменить знак, сделав аргумент неотрицательным.\r\nЗатем если x>1, обратить его: x=1/x.\r\nЗатем сокращаем область определения (запоминая число сделанных шагов), используя формулу\r\n\r\nдо тех пор, пока x не окажется в интервале [0,pi/12]. \r\nПосле этого можно вычислять y=arctg(x) по формуле Тейлора.\r\nСместим результат y на p/6 необходимое число раз\r\nЕсли x было больше 1, то результат \r\nЕсли x было отрицательным, то результат \r\n\r\n

private double MArctg(double x0) {\r\n  int sp=0;\r\n  double x,x2,y;\r\n  x=x0;\r\n  if(x<0) {x=-x;}\r\n  if(x>1) {x=1.0/x;}\r\n  //Уменьшаем интервал области аргумента\r\n  while(x>0.2617993877991495) {\r\n    sp++; //Вспомогательный счетчик шагов \r\n    x=(x1.732050807569-1)/(x+1.732050807569);\r\n  }\r\n  //Вычисляем ряд Тейлора\r\n    y=x;\r\n    int n=1;\r\n    double sn=x; \r\n    while (sn>1E-16){\r\n            sn=sn(2+1.0/n)0.5xx;\r\n            y=y+sn/(2n+1)/(2n+1); \r\n            n=n+1;\r\n    }\r\n        \r\n  //Смещаем все на pi/6 необходимое число раз \r\n  y=y+sp0.523598775598 \r\n \r\n  if(x0>1) a=0.2617993877991495-a;\r\n  if(x0<0) y=-y;\r\n \r\n  return y;\r\n}\r\n

\r\n\r\n08 мая 2008 г.

No comments yet! Why don't you be the first?

Post Comment

Your email address will not be published. Required fields are marked *