画二元函数图像_二元函数怎么画图

画二元函数图像_二元函数怎么画图目录概述字符串表达式解析图像绘制函数作为属性赋值参考以及说明概述本篇博客主要是在上一篇《每个人都该懂点函数式编程》的基础上,进一步说明“函数”在函数式编程中的重要作用。强调了函数和普通类型一样,可以赋

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

目录

 

概述

本篇博客主要是在上一篇《每个人都该懂点函数式编程》的基础上,进一步说明“函数”在函数式编程中的重要作用。强调了函数和普通类型一样,可以赋值、存储、传参以及作为另外函数的返回值。

本文附带了一个Demo,该Demo可以将任意字符串函数表达式解析之后生成对应的函数(一元、二元以及三元),如果你输入的是一元或者二元函数表达式,则可以绘制出相应的函数图像。一元函数图像为平面曲线,二元函数图像为立体曲面。看下图:

画二元函数图像_二元函数怎么画图

画二元函数图像_二元函数怎么画图

函数表达式中只识别X、Y、Z三个自变量。

Github源码下载

 

字符串表达式解析

字符串解析是重点。

怎样去识别一串字符串函数表达式呢?如x^2+sin(x)*cos(y)。之后怎样去计算函数值呢?其实原理很简单,由于每个函数表达式中包含的有效符号是有限的,如X、Y、Z、+、-、*、/以及一些函数诸如log、sin、cos等等,只要我们将这些有效符号均识别筛选出来之后,再根据这些符号的优先级别生成一个函数语法树即可。

画二元函数图像_二元函数怎么画图

如上图所示,使用一个“树结构”去存储最终的语法树。最后带入X、Y(二元)求得函数值。

表达式解析这块难点是语法树的构建和最终求值。语法树的构建有点复杂,大家可以参见源码;最终求值的原理是,判断当前符号(节点)是单目运算符号(如cos、sin、负号等)还是双目运算符号(如+ – * /等),如果是单目运算比如cos函数,则先计算子节点(只有一个子节点)的值,然后将得到的值进行cos运算(Math.Cos(子节点的值));相反,如果是双目运算符比如+符号,那么先计算左子节点和右子节点的值,最后将两个值进行+操作(左子节点的值+右子节点的值),依次递归计算得到最终的函数值。

 

图像绘制

图像绘制这块就比较简单了。根据前一步得到的语法树,我们可以创建出对应的一元函数、二元函数以及三元函数(委托的形式)。事先定义的委托结构如下:

    /// <summary>
    /// 一元函数
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    public delegate double UnaryFunction(double x);
    /// <summary>
    /// 二元函数
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public delegate double BinaryFunction(double x,double y);
    /// <summary>
    /// 三元函数
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="z"></param>
    /// <returns></returns>
    public delegate double MultiFunction(double x,double y,double z);

很简单就可以看出,一元函数接收一个参数,返回一个值;二元函数接收两个参数,返回一个值;三元函数接收三个参数,返回一个值。生成委托的过程如下:

   (UnaryFunction)((double x) => { return root.GetValue(x, 0, 0); });
   (BinaryFunction)((double x, double y) => { return root.GetValue(x, y, 0); });
   (MultiFunction)((double x, double y, double z) => { return root.GetValue(x, y, z); });

最终给出对应的x、y、z调用委托,即可得到函数值。

一元函数绘制

随便对X取一个区间(如[-10,10]),以0.1为间距,计算每个X对应的Y值(函数值)。最终将这些点连接起来,出来的就是对应的一元函数图像。

二元函数绘制

相似的,随便对X、Y取一个区间(如X取[-10,10],Y取[-10,10]),X、Y均以0.1为间距,计算每个(X、Y)对应的Z值(函数值),最后将这些三维点绘制成曲面。

 

函数作为属性赋值

经过前几步得到了函数(委托对象),我们直接将委托对象作为属性赋给图像绘制控件,绘图控件更新界面。

   //一元
   if (textBox1.Text.ToLower().Contains('x') && !textBox1.Text.ToLower().Contains('y') && !textBox1.Text.ToLower().Contains('z'))
   {
       UnaryFunction func = (new SyntaxManager().ParseUnaryFunction(textBox1.Text));
       unaryFunctionDrawingBoard1.Function = func;
       tabControl1.SelectedIndex = 0;
   }
   //二元
   else if (textBox1.Text.ToLower().Contains('x') && textBox1.Text.ToLower().Contains('y') && !textBox1.Text.ToLower().Contains('z'))
   {
       BinaryFunction func = (new SyntaxManager().ParseBinaryFunction(textBox1.Text));
       binaryFunctionDrawingBoard1.BinaryFunction = func;
       tabControl1.SelectedIndex = 1;
   }
   //三元
   else
   {
        MultiFunction func = (new SyntaxManager().ParseMultiFunction(textBox1.Text));
        MessageBox.Show("三元函数图像无法绘制!");
   }

如上代码,函数作为属性赋值的示例。

 

参考及说明

1.Demo中有关3D图形绘制参考了网上的一个OpenTK的demo:http://download.csdn.net/detail/dragonflies/3418135#comment

2.函数图像在线生成(为了验证demo生成的图像是否正确)

3.注意 函数绘制时没有做任何区间验证,比如logX中的X不能为负,否则无效(绘制时异常)。这些需要自己注意。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/166555.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【数据分析报告】携程客户分析与流失预测

    【数据分析报告】携程客户分析与流失预测目录一、项目背景与目的二、探索性分析2.1数据指标预览2.2数据概况2.3数据分布2.3.1数据分布总览2.3.2预定日期和入住日期2.3.3访问时间段2.3.4客户价值2.3.5消费能力指数2.3.6价格敏感指数分布2.3.6入住酒店平均价格2.3.7酒店星级偏好2.3.8订单取消率2.3.9用户年订单数分布2.3.10新老客户流失率三、数据预处理3.1去除不需要的字段与重复字段3.2数据类型转换3.3异常值处理3.3.1负数处理3.3.2极值处理3.4缺失值处理3.

    2022年10月18日
    4
  • browserify使用「建议收藏」

    browserify使用「建议收藏」一、简介browserift是javascript编译工具,可以通过预编译方式,将后端的node模块加入javascript中,进而可在前端浏览器上执行。二、安装1、安装nodejs和npmnodejs是node的运行环境,npm是node的包管理工具。它们的安装在此略过(可参数本博客其它文章)。2、browserify安装命令:npminstall-gbrowserify三、使…

    2025年7月3日
    2
  • 一个完美的世界 访问

    一个完美的世界 访问

    2022年1月7日
    71
  • BufferedWriter[通俗易懂]

    BufferedWriter[通俗易懂]  带有默认缓冲的字符输出流。使用:  构造:BufferedWriterbf=newBufferedWriter(“outFilePath”);  写入:write(“thing”);  换行:newLine();  刷新缓冲区,会将内容写进目标文件:flush();  关闭该流的操作:close();importjava.io.BufferedWrit…

    2022年5月1日
    45
  • Git合并分支超详细解释

    Git合并分支超详细解释摘自朱双印老师博客 http www zsythink net archives 3470 在执行 合并 操作时 我们可以根据具体情况 选择不同的合并模式去合并 不同的合并模式对应了不同的命令参数 而且在合并的过程中 还可能遇到 冲突 为了说明白原理 我们先来看一些示意图此示意图并没有涉及到任何合并操作 而是描述了合并分支之前 两个分支的创建过程 上图中的第 1 步表示已经存在的一条分支 这条分支的名字是 base 第 2 步表示基于 base 分支 创建了 new 分支 此时 base 分支的指针和 new 分支的

    2025年7月12日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号