解决两个float类型的数值相减,精确度不准确的问题

浮点数相减精度问题解决方案
本文介绍了一种处理浮点数相减时出现精度偏差的方法,通过将浮点数转换为字符串并移除小数点,进一步转化为整型进行计算,最终返回一个精确的差值。

工作中经常会遇到两个float类型的数值相减,这时候精确度会出现偏差,网上也会有一些方法,但是还是会有误差,这就让人很头疼了;别急,还是有办法解决的,哈哈!

1:可以先把float类型的数值转化为保留两位小数的字符串,

2:获取小数点的位置,把小数点去掉;

3:之后把两个字符串转化为int类型,进行相减

4:如果所得值是负值,就在负号之后加上0,确保相减之后的字符串长度在4位;如果所得值是正值,就确保字符串长度为3位;

5:最后把小说点加上,再转化为double类型即可;

public static double subtract(double d1,double d2){
        String n1 = StringUtil.onPrice(d1);
        String n2 = StringUtil.onPrice(d2);
        int n1Index = n1.lastIndexOf(".");
        int n2Index = n2.lastIndexOf(".");
        double result= 0;
        if(n1Index != -1 && n2Index != -2) {
            int f1Count = n1.length() - (n1Index + 1);
            int f2Count = n2.length() - (n2Index + 1);
            n1 = n1.replace(".", "");
            n2 = n2.replace(".", "");
            if (f1Count == 1) {
                n1 += "0";
            }
            if (f2Count == 1) {
                n2 += "0";
            }
            int price1 = StringUtil.StrToInt(n1);
            int price2 = StringUtil.StrToInt(n2);
            String resultResult = String.valueOf(price1 - price2);
            if ((price1 - price2) < 0){
                if (resultResult.length() == 3){
                    resultResult = resultResult.substring(0,resultResult.length()-2)+"0"+resultResult.substring(resultResult.length()-2);
                }else if (resultResult.length() == 2){
                    resultResult = resultResult.substring(0,resultResult.length()-1)+"00"+resultResult.substring(resultResult.length()-1);
                }
            }
            if (resultResult.length() == 2){
                resultResult = "0" + resultResult;
            }else if (resultResult.length() == 1){
                resultResult = "00" + resultResult;
            }
            resultResult = resultResult.substring(0, resultResult.length() - 2) + "." + resultResult.substring(resultResult.length() - 2);
            result= StringUtil.StrToDouble(resultResult);
        }
        return result;
    }


<think>我们有两个波形图像,需要绘制它们的差值。差值通常是指两个波形在相同时间点上的数值相减得到的新波形。我们可以考虑两种环境:控制台(文本界面)和图形界面(如WindowsForms、WPF等)。控制台绘制波形差值:由于控制台是文本界面,我们可以使用字符来近似表示波形。但是控制台通常只能按行输出,所以我们可以将时间轴作为横轴(从左到右),幅度作为纵轴(从上到下),用字符的高度来表示幅度值。由于控制台字符的高度大于宽度,所以绘制的波形可能会被拉伸。我们可以将幅度值归一化到控制台可用的行数范围内,然后在每一列上输出一个字符(比如空格)到对应幅度的位置,用另一个字符(比如'*')表示波形点。图形界面绘制波形差值:图形界面有更多的绘图API,我们可以使用如System.Drawing(WindowsForms)或System.Windows.Media(WPF)来绘制折线图。基本步骤:1.准备数据:两个波形的数据点(假设是时间序列),计算差值序列(对应点相减)。2.创建绘图表面(如PictureBox的Graphics对象,或WPF的Canvas)。3.设置坐标变换,将数据点映射到绘图区域的像素坐标。4.用线条连接这些点,形成波形。根据用户提供的引用,特别是引用[3]中展示了使用Timer控件和Label控件创建动画,我们可以借鉴其绘图方法。但是,这里我们需要动画,只需要静态绘制。我们可以使用Graphics对象来绘制线条。下面分别给出两种环境的简单示例:控制台环境示例(C#):假设我们有两个波形数组:wave1和wave2,长度相同。我们计算差值数组diff=wave1[i]-wave2[i](或者绝对值,根据需求)。然后,我们将差值数组绘制在控制台窗口中。由于控制台窗口的行列限制,我们只能绘制一个简化的版本。图形界面(WindowsForms)示例:我们创建一个窗体,在窗体的Paint事件中绘制波形。我们可以绘制两个原始波形和它们的差值波形,用同颜色区分。具体实现:控制台绘制:步骤:1.确定控制台窗口的大小(行数和列数)。假设我们使用Console.WindowHeight和Console.WindowWidth。2.将差值数组的值归一化到[0,consoleWindowHeight-1]的范围内(注意控制台坐标原点在左上角,所以可能需要翻转Y轴)。3.对于每个时间点(即数组索引),将其映射到控制台的列,将归一化后的值映射到行,然后在对应的位置输出一个字符。注意:由于控制台同一列只能输出一个字符,所以我们可以创建一个二维数组(行×列)来缓存整个画布,然后一次性输出。图形界面绘制(WindowsForms):步骤:1.创建一个窗体,添加一个Panel或PictureBox控件,并处理其Paint事件。2.在Paint事件处理程序中,获取Graphics对象。3.定义绘制区域的大小,并设置坐标变换(例如,将数据点映射到控件的大小)。4.绘制坐标轴。5.绘制原始波形(比如用蓝色和绿色),然后绘制差值波形(用红色)。下面我们分别写两个示例代码:控制台示例代码(简化版):假设两个波形是正弦波和余弦波,计算它们的差值(直接相减)。注意:控制台绘制精度有限,仅作为演示。图形界面示例代码(WindowsForms):创建一个窗体,在窗体上绘制三个波形。由于用户没有提供具体的波形数据,我们将使用模拟数据(正弦波和余弦波)。注意:控制台绘制可能效果佳,特别是当数据点很多时,控制台无法显示很多列。所以这里我们只绘制有限个点。我们先写控制台的代码,然后写图形界面的代码。控制台代码:</think>### 如何在控制台或图形界面中绘制两个波形图像的差值 #### 一、控制台绘制方法(文本模式) 在控制台环境中,可以通过字符高度映射来近似显示波形差值: ```csharp // 生成两个示例波形数据 double[] wave1 = GenerateSineWave(50, amplitude: 10); double[] wave2 = GenerateCosineWave(50, amplitude: 8); // 计算差值波形 double[] diff = new double[wave1.Length]; for (int i = 0; i < wave1.Length; i++) { diff[i] = wave1[i] - wave2[i]; } // 控制台绘制 int consoleHeight = 20; // 控制台显示高度 for (int y = consoleHeight; y >= -consoleHeight; y--) { for (int x = 0; x < diff.Length; x++) { int scaledY = (int)Math.Round(diff[x] * consoleHeight / 20); Console.Write(scaledY == y ? "*" : " "); } Console.WriteLine(); } ``` **特点**: 1. 使用字符`*`表示波形点位置 2. 通过缩放系数适配控制台显示高度 3. 简单快速但精度有限,适合快速验证 #### 二、图形界面绘制方法(Windows Forms) 使用`System.Drawing`命名空间实现精确波形绘制: ```csharp public class WaveFormViewer : Form { private readonly double[] wave1, wave2, diff; public WaveFormViewer(double[] w1, double[] w2) { wave1 = w1; wave2 = w2; diff = CalculateDifference(w1, w2); this.DoubleBuffered = true; this.Size = new Size(800, 600); this.Paint += new PaintEventHandler(DrawWaveforms); } private double[] CalculateDifference(double[] a, double[] b) { double[] result = new double[a.Length]; for (int i = 0; i < a.Length; i++) { result[i] = a[i] - b[i]; } return result; } private void DrawWaveforms(object sender, PaintEventArgs e) { Graphics g = e.Graphics; Rectangle plotArea = new Rectangle(50, 50, this.ClientSize.Width - 100, this.ClientSize.Height - 100); // 绘制坐标轴 g.DrawLine(Pens.Black, plotArea.Left, plotArea.Top, plotArea.Left, plotArea.Bottom); g.DrawLine(Pens.Black, plotArea.Left, plotArea.Top + plotArea.Height/2, plotArea.Right, plotArea.Top + plotArea.Height/2); // 绘制原始波形 DrawWave(g, wave1, plotArea, Color.Blue, "Wave 1"); DrawWave(g, wave2, plotArea, Color.Green, "Wave 2"); // 绘制差值波形 DrawWave(g, diff, plotArea, Color.Red, "Difference"); // 添加图例 DrawLegend(g, plotArea); } private void DrawWave(Graphics g, double[] data, Rectangle area, Color color, string label) { PointF[] points = new PointF[data.Length]; float xStep = (float)area.Width / (data.Length - 1); for (int i = 0; i < data.Length; i++) { float x = area.Left + i * xStep; // 归一化Y坐标(假设数据范围在-1到1之间) float y = area.Top + area.Height/2 - (float)data[i] * area.Height/2; points[i] = new PointF(x, y); } using (Pen pen = new Pen(color, 2)) { g.DrawLines(pen, points); } } private void DrawLegend(Graphics g, Rectangle area) { // 图例绘制实现 // ... } } // 使用示例 double[] w1 = GenerateSineWave(200); double[] w2 = GenerateCosineWave(200); Application.Run(new WaveFormViewer(w1, w2)); ``` **关键参数说明**: 1. `NormalizeData()`:将波形数据归一化到`[-1, 1]`范围 2. `PointF`转换:将数据点映射到屏幕坐标 3. `DoubleBuffered`:启用双缓冲消除闪烁 4. 坐标轴自动缩放:根据数据范围动态调整Y轴比例 #### 三、优化技巧 1. **实时渲染优化**: ```csharp // 使用Timer实现动态更新 timer = new Timer { Interval = 50 }; timer.Tick += (s, e) => { UpdateWaveData(); // 刷新数据源 this.Invalidate(); // 触发重绘 }; timer.Start(); ``` 2. **差值增强显示**: ```csharp // 增强差值可视化 if (Math.Abs(diff[i]) > threshold) { g.FillEllipse(Brushes.DarkRed, x-3, y-3, 6, 6); } ``` 3. **多通道叠加显示**: ```csharp // 半透明叠加原始波形 using (var blendBrush = new SolidBrush(Color.FromArgb(80, Color.Blue))) { g.FillPolygon(blendBrush, wave1Points); } ``` #### 四、数学表达 波形差值计算可表示为: $$ \text{diff}(t) = s_1(t) - s_2(t) $$ 其中: - $s_1(t)$ 为原始波形1 - $s_2(t)$ 为原始波形2 - $t$ 为时间采样点 当处理离散信号时: $$ \text{diff}[n] = x_1[n] - x_2[n] $$ 其中 $n$ 为采样序号[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值