工作之余,突然想用java写一套数值计算的算法套件,权当练手。当然要包括后台和前台,先整后台,具体算法部分。前台考虑web端做个类似“计算器”的东东,等有空再说吧。
算法
首先第一天,先来个复数运算。这其中的数学原理就先略过了,当然如果有需要,以后再补充。先来一段源码先:
package com.mysite.algorithm.model;
import lombok.Data;
import lombok.ToString;
import java.util.*;
import java.math.*;
@Data
public class Complex {
private Doublereal =0.0;
private Doubleimaginary =0.0;
private Doubleeps =0.0;//默认精度
public Complex(Double r, Double i){
this.real = r;
this.imaginary = i;
}
public Complex(Complex c){
this.real = c.getReal();
this.imaginary = c.getImaginary();
}
public Boolean Equals(Object o){
Complex c = (Complex)o;
if(c ==null)return false;
return Math.abs(this.real - c.getReal()) <=this.eps &&
Math.abs(this.imaginary - c.getImaginary()) <=this.eps;
}
public Complex Add(Complex c){
Double r =this.real + c.getReal();
Double i =this.imaginary + c.getImaginary();
return new Complex(r,i);
}
public Complex Subtract(Complex c){
Double r =this.real - c.getReal();
Double i =this.imaginary - c.getImaginary();
return new Complex(r,i);
}
public Complex Multiply(Complex c){
Double r =this.real * c.getReal() -this.imaginary * c.getImaginary();
Double i =this.real * c.getImaginary() +this.imaginary * c.getReal();
return new Complex(r,i);
}
public Complex Devide(Complex c){
Double e,f,x,y;
if(Math.abs(c.getReal()) >= Math.abs(c.getImaginary())){
e = c.getImaginary() / c.getReal();
f= c.getReal() + e * c.getImaginary();
x = (this.real +this.imaginary * e)/f;
y = (this.imaginary -this.real * e)/f;
}else{
e= c.getReal() / c.getImaginary();
f = c.getImaginary()+ e * c.getReal();
x = (this.real * e +this.imaginary)/f;
y = (this.imaginary *e -this.real)/f;
}
return new Complex(x,y);
}
public Double Abs(){
return Math.sqrt(this.real *this.real +this.imaginary *this.imaginary);
}
// 返回共轭复数
public Complex Conjuagte(){
return new Complex(this.real ,0.0 -this.imaginary);
}
// 求复数的N次方根
public List Root(Integer n){
List ret =new ArrayList<>();
if(n <1)return null;
Double q = Math.atan2(this.imaginary,this.real);
Double r = Math.sqrt(this.real*this.real +this.imaginary *this.imaginary);
if(r!=0){
r = (1.0 /n) * Math.log(r);
r = Math.exp(r);
}
for(Integer k =0;k <= n-1; k++){
Double t = (2.0 *k*Math.PI + q)/n;
Complex complex =new Complex(r*Math.cos(t), r* Math.sin(t));
ret.add(complex);
}
return ret;
}
// 计算复数的实幂指数
public Complex Pow(Double p){
Double r,t;
if(this.imaginary ==0 &&this.real ==0)return new Complex(0.0,0.0);
if(this.real ==0){
if(this.imaginary >0){
t = Math.PI /2;
}else {
t = -Math.PI/2;
}
}
else {
if(this.real >0){
t = Math.atan2(this.imaginary,this.real);
}
else{
if(this.imaginary >0){
t = Math.atan2(this.imaginary,this.real) + Math.PI;
}else{
t = Math.atan2(this.imaginary,this.real) - Math.PI;
}
}
}
r = Math.exp(p * Math.log(Math.sqrt(this.real *this.real +this.imaginary *this.imaginary)));
return new Complex(r* Math.cos(p * t), r* Math.sin(p * t));
}
// 计算复数的复幂指数
public Complex Pow(Complex p, Integer n){
Double r,s,u,v;
if(this.real ==0){
if(this.imaginary ==0)return new Complex(0.0,0.0);
s = Math.PI /2 * (Math.abs(this.imaginary)/this.imaginary +4*n);
}else{
s =2 * Math.PI * n + Math.atan2(this.imaginary,this.real);
if(this.real <0){
s =this.imaginary >0 ? s + Math.PI : s - Math.PI;
}
}
r =0.5 * Math.log(this.real *this.real +this.imaginary *this.imaginary);
v = p.getReal() * r + p.getImaginary() * s;
u = Math.exp(p.getReal() * r - p.getImaginary() * s);
return new Complex(u * Math.cos(v), u * Math.sin(v));
}
// 求复数的自然对数
public Complex Log(){
Double p = Math.log(Math.log(Math.sqrt(this.real *this.real +this.imaginary *this.imaginary)));
return new Complex(p, Math.atan2(this.imaginary,this.real));
}
// 求复数的正弦
public Complex Sin(){
Double p[] = sincos();
Double x = p[0], y = p[1];
return new Complex( x * Math.sin(this.real), y * Math.cos(this.real));
}
// 求复数的余弦
public Complex Cos(){
Double p[] = sincos();
Double x = p[0], y = p[1];
return new Complex( x * Math.cos(this.real), -y * Math.sin(this.real));
}
private Double[] sincos(){
Integer i;
Double x,y ,y1,br =0.0, b1 =0.0, b2 =0.0;
//切比雪夫公式的常数系数
Double c[] =new Double[6];
c[0] =1.13031820798597;
c[1] =0.04433684984866;
c[2] =0.00054292631191;
c[3] =0.00000319843646;
c[4] =0.00000001103607;
c[5] =0.00000000002498;
y1 = Math.exp(this.imaginary);
x =0.5 * (y1 +1/y1);
if(Math.abs(this.imaginary) >=1){
y =0.5 * (y1 -1/y1);
}else{
y1 =2 * (2 *this.imaginary *this.imaginary -1);
for(i =5;i >=0;--i){
br = y1 * b1 - b2 - c[i];
if(i !=0){
b2 = b1;
b1 = br;
}
}
y =this.imaginary * (br - b1);
}
Double ret[] =new Double[2];
ret[0] = x;
ret[1] = y;
return ret;
}
// 计算复数的正切
public Complex Tan(){
return Sin().Devide(Cos());
}
}
验证
包括了基本运算法则加减乘除还有幂,方根等,基本够用了。那么如何验证我们的代码是否正确呢?这个时候可以借助科学计算领域的大神python,同样的算式看看两边计算的结果是否相等就可以了。
测试代码如下:
private static void TestComplex(){
Complex a = new Complex(2.0,4.0);
Complex b = new Complex(3.0,-5.0);
System.out.println(a.ToString());
System.out.println("a+b:" + a.Add(b));
System.out.println("a-b:" + a.Subtract(b));
System.out.println("a*b:" + a.Multiply(b));
System.out.println("a/b:" + a.Devide(b));
System.out.println("sin(a):" + a.Sin());
System.out.println("cos(a):" + a.Cos());
System.out.println("sqrt(a)" + a.Root(2));
}
运行结果如下:
a+b:Complex(real=5.0, imaginary=-1.0, eps=0.0)
a-b:Complex(real=-1.0, imaginary=9.0, eps=0.0)
a*b:Complex(real=26.0, imaginary=2.0, eps=0.0)
a/b:Complex(real=-0.4117647058823529, imaginary=0.6470588235294118, eps=0.0)
sin(a):Complex(real=24.83130584894638, imaginary=-11.356612711218173, eps=0.0)
cos(a):Complex(real=-11.36423470640106, imaginary=-24.814651485634183, eps=0.0)
sqrt(a)[Complex(real=1.7989074399478673, imaginary=1.1117859405028423, eps=0.0), Complex(real=-1.7989074399478673, imaginary=-1.111785940502842, eps=0.0)]
用python进行同样的计算,结果如下:
import cmath
a = complex(2,4)
b = 3-5j
a+b
(5-1j)
a-b
(-1+9j)
a*b
(26+2j)
a/b
(-0.4117647058823529+0.6470588235294118j)
cmath.sin(a)
(24.83130584894638-11.356612711218174j)
cmath.cos(a)
(-11.36423470640106-24.814651485634187j)
cmath.sqrt(a)
(1.7989074399478673+1.1117859405028423j)
···
可见二者的结果是一致的,我们的算法正确(其他情况请自行验证)。好了,今天就到此为止了。
网友评论