如何使用 Java 中的 BigDecimal 获得正弦值的准确结果?
How do you get accurate results for sine values with BigDecimal in Java?
我的目标是生成准确的正弦波。我的问题是,当我使用 BigDecimal 和 StrictMath 生成值时,一些过零点是错误的并且对称性被破坏了。
这是一个频率为1、相位为0、振幅为1、时间为1秒、采样率为10的数组(我会post后面的代码这个 post):
>[0] 0.0
>[1] 0.5877852522924731
[2] 0.9510565162951535
[3] 0.9510565162951536
[4] 0.5877852522924732
[5] 1.2246467991473532E-16
[6] -0.587785252292473
[7] -0.9510565162951535
>[8] -0.9510565162951536
>[9] -0.5877852522924734
[5] 不应该为 0 以确保准确性吗?不应该 (4 = 1) 以及 (2 = 3)、(9 = 6) 和 (7 = 8)?
第二种情况,相位等于 StrictMath.PI/2.0 似乎在 [5]:
处产生精度
>[0] 1.0
>[1] 0.8090169943749475
[2] 0.3090169943749475
[3] -0.3090169943749473
>[4] -0.8090169943749473
>[5] -1.0
[6] -0.8090169943749476
>[7] -0.3090169943749476
>[8] 0.3090169943749472
[9] 0.8090169943749472
在这种情况下,起点不太准确,[5] 更准确,但再一次,不应该 (-4 = 1) 以及 (-2 = 3),(-9 = 6) 和 (-7 = 8)?
所以我的问题是为什么会这样?为什么过零错误,但 1 和 -1 交叉正确?为什么正弦对称性破缺?
这是我生成值的代码:
package Wave;
import java.math.BigDecimal;
/**
* @author Alexander Johnston
* Copyright 2019
* A class for sine waves
*/
public class SineWave extends Wave {
/** Creates a sine wave
* @param a as the amplitude of the sin wave from -amplitude to amplitude
* @param f as the frequency of the sine wave in Hz
* @param p as the phase of the sine wave
*/
public SineWave(BigDecimal a, BigDecimal f, BigDecimal p) {
this.a = a;
this.f = f;
this.p = p;
}
/* (non-Javadoc)
* @see waves.Wave#getSample(BigDecimal, float)
*/
public double[] getSample(BigDecimal t, float sr) {
int nsd;
BigDecimal nsdp = (new BigDecimal(Float.toString(sr)).multiply(t));
if(nsdp.compareTo(new BigDecimal(Integer.MAX_VALUE)) == -1) {
nsd = nsdp.intValue();
} else {
System.out.print("wave time is too long to fit in an array");
return null;
}
double[] w = new double[nsd];
for(int i = 0; i < w.length; i++) {
w[i] = a.multiply(new BigDecimal(StrictMath.sin(((new BigDecimal(2.0).multiply(new BigDecimal(StrictMath.PI)).multiply(f).multiply(new BigDecimal(i)).divide((new BigDecimal(Float.toString(sr))))).add(p)).doubleValue()))).doubleValue();
}
p = p.add(new BigDecimal(2.0).multiply(new BigDecimal(StrictMath.PI).multiply(f).multiply(t)));
return w;
}
}
The wave class:
package Wave;
import java.math.BigDecimal;
/**
* @author Alexander Johnston
* Copyright 2019
* A class for waves to extend
*/
public abstract class Wave {
// Amplitude of the wave
protected BigDecimal a;
// Frequency of the wave in Hz
protected BigDecimal f;
// Phase of the wave, between 0 and (2*Math.PI)
protected BigDecimal p;
/** Generates a wave with with the correct amplitude
* @param t as the length of the wave in seconds
* @return An array with the wave generated with specified amplitude as amplitude over time
*/
abstract public double[] getSample(BigDecimal t, float sr);
}
和主要方法:
import java.math.BigDecimal;
import Wave.SineWave;
public class main {
public static void main(String[] args) {
BigDecimal a = new BigDecimal(1.0);
BigDecimal f = new BigDecimal(1.0);
BigDecimal p = new BigDecimal(0.0);
SineWave sw = new SineWave(a, f, p);
p = new BigDecimal(StrictMath.PI).divide(new BigDecimal(2.0));
SineWave swps = new SineWave(a, f, p);
BigDecimal t = new BigDecimal(1.0);
float sr = 10;
// The first array in this post
double [] swdns = sw.getSample(t, sr);
// The second array in this post
double [] swpsdns = swps.getSample(t, sr);
}
感谢您抽出宝贵时间查看我的post。非常感谢您的帮助。
按照 Erwin 的建议,我找到了一个适合我需要的图书馆。
BigDecimalMath
它有一个慷慨的许可,当我将精度设置为 1074 位小数时,它解决了我对这些特定数组的问题,这是 Java 原始双精度值的负指数的最大绝对值。
再次感谢欧文的帮助!
我的目标是生成准确的正弦波。我的问题是,当我使用 BigDecimal 和 StrictMath 生成值时,一些过零点是错误的并且对称性被破坏了。
这是一个频率为1、相位为0、振幅为1、时间为1秒、采样率为10的数组(我会post后面的代码这个 post):
>[0] 0.0
>[1] 0.5877852522924731
[2] 0.9510565162951535
[3] 0.9510565162951536
[4] 0.5877852522924732
[5] 1.2246467991473532E-16
[6] -0.587785252292473
[7] -0.9510565162951535
>[8] -0.9510565162951536
>[9] -0.5877852522924734
[5] 不应该为 0 以确保准确性吗?不应该 (4 = 1) 以及 (2 = 3)、(9 = 6) 和 (7 = 8)?
第二种情况,相位等于 StrictMath.PI/2.0 似乎在 [5]:
处产生精度>[0] 1.0
>[1] 0.8090169943749475
[2] 0.3090169943749475
[3] -0.3090169943749473
>[4] -0.8090169943749473
>[5] -1.0
[6] -0.8090169943749476
>[7] -0.3090169943749476
>[8] 0.3090169943749472
[9] 0.8090169943749472
在这种情况下,起点不太准确,[5] 更准确,但再一次,不应该 (-4 = 1) 以及 (-2 = 3),(-9 = 6) 和 (-7 = 8)?
所以我的问题是为什么会这样?为什么过零错误,但 1 和 -1 交叉正确?为什么正弦对称性破缺?
这是我生成值的代码:
package Wave;
import java.math.BigDecimal;
/**
* @author Alexander Johnston
* Copyright 2019
* A class for sine waves
*/
public class SineWave extends Wave {
/** Creates a sine wave
* @param a as the amplitude of the sin wave from -amplitude to amplitude
* @param f as the frequency of the sine wave in Hz
* @param p as the phase of the sine wave
*/
public SineWave(BigDecimal a, BigDecimal f, BigDecimal p) {
this.a = a;
this.f = f;
this.p = p;
}
/* (non-Javadoc)
* @see waves.Wave#getSample(BigDecimal, float)
*/
public double[] getSample(BigDecimal t, float sr) {
int nsd;
BigDecimal nsdp = (new BigDecimal(Float.toString(sr)).multiply(t));
if(nsdp.compareTo(new BigDecimal(Integer.MAX_VALUE)) == -1) {
nsd = nsdp.intValue();
} else {
System.out.print("wave time is too long to fit in an array");
return null;
}
double[] w = new double[nsd];
for(int i = 0; i < w.length; i++) {
w[i] = a.multiply(new BigDecimal(StrictMath.sin(((new BigDecimal(2.0).multiply(new BigDecimal(StrictMath.PI)).multiply(f).multiply(new BigDecimal(i)).divide((new BigDecimal(Float.toString(sr))))).add(p)).doubleValue()))).doubleValue();
}
p = p.add(new BigDecimal(2.0).multiply(new BigDecimal(StrictMath.PI).multiply(f).multiply(t)));
return w;
}
}
The wave class:
package Wave;
import java.math.BigDecimal;
/**
* @author Alexander Johnston
* Copyright 2019
* A class for waves to extend
*/
public abstract class Wave {
// Amplitude of the wave
protected BigDecimal a;
// Frequency of the wave in Hz
protected BigDecimal f;
// Phase of the wave, between 0 and (2*Math.PI)
protected BigDecimal p;
/** Generates a wave with with the correct amplitude
* @param t as the length of the wave in seconds
* @return An array with the wave generated with specified amplitude as amplitude over time
*/
abstract public double[] getSample(BigDecimal t, float sr);
}
和主要方法:
import java.math.BigDecimal;
import Wave.SineWave;
public class main {
public static void main(String[] args) {
BigDecimal a = new BigDecimal(1.0);
BigDecimal f = new BigDecimal(1.0);
BigDecimal p = new BigDecimal(0.0);
SineWave sw = new SineWave(a, f, p);
p = new BigDecimal(StrictMath.PI).divide(new BigDecimal(2.0));
SineWave swps = new SineWave(a, f, p);
BigDecimal t = new BigDecimal(1.0);
float sr = 10;
// The first array in this post
double [] swdns = sw.getSample(t, sr);
// The second array in this post
double [] swpsdns = swps.getSample(t, sr);
}
感谢您抽出宝贵时间查看我的post。非常感谢您的帮助。
按照 Erwin 的建议,我找到了一个适合我需要的图书馆。 BigDecimalMath 它有一个慷慨的许可,当我将精度设置为 1074 位小数时,它解决了我对这些特定数组的问题,这是 Java 原始双精度值的负指数的最大绝对值。
再次感谢欧文的帮助!