C#实现求解函数在某一点的切线与法线函数

csharp 复制代码
using MathNet.Symbolics; 
using System.Text;

private string ConvertToLatex(string mathExpression)
{
    return mathExpression
        .Replace(" * ", "")
        .Replace("*", "")
        .Replace("π",@"\pi")
        .Replace("sin(x)", @"\sin x") 
        .Replace("cos(x)", @"\cos x")
        .Replace("tan(x)", @"\tan x")
        .Replace("cot(x)", @"\cot x")
        .Replace("sec(x)", @"\sec x")
        .Replace("csc(x)", @"\csc x");
}

private string calculate_trigonometric_functions(string expression, bool isLatexFormat = false)
{
    string ret = expression;
    if (expression.Contains("sin(π/3)"))
    {
        /* 
        公式:sin(π/3) = √3/2
        证明:sin(π/3)等于根号三除以2,即√3/2。这是因为在单位圆上,角度π/3对应的弧度是60度,它是一个等边三角形的内角,三角函数sin对应的是对边与斜边的比值,而等边三角形的对边和斜边长度相等,都是边长的根号三倍。因此,sin(π/3)等于根号三除以2。
        */
        ret = ret.Replace("sin(π/3)", isLatexFormat ? "\\frac{\\sqrt{3}}{2}" : "sqrt(3)/2");
    }
    if (expression.Contains("cos(π/3)"))
    {
        /*
        公式:cos(π/3) = 1/2
        证明:考虑一个边长为1的等边三角形,其中每个内角都是60度(π/3弧度)。从一个顶点作垂线到对边,这将等边三角形分割成两个30-60-90的直角三角形。在这样的直角三角形中,较短的直角边(对应于60度角的邻边)是斜边(等边三角形的边)的一半,即1/2。由于余弦函数定义为邻边与斜边的比值,在60度角(π/3弧度)的情况下,这个比值就是1/2。
        */
        ret = ret.Replace("cos(π/3)", isLatexFormat ? "\\frac{1}{2}" : "1/2");
    }
    if (expression.Contains("tan(π/3)"))
    {
        /*
        公式:tan(π/3) = √3
        证明:在直角三角形中,当其中一个锐角是60度时,这个角的对边与邻边的比值遵循特定的比例。具体来说,如果将这个直角三角形的斜边视为单位长度(即1),那么对边(对应于60度角的边)长度为√3,邻边长度为1。因此,根据正切(tan)的定义,即对边与邻边的比值,我们有tan(60°) = tan(π/3) = 对边/邻边 = √3/1 = √3。
        */
        ret = ret.Replace("tan(π/3)", isLatexFormat ? "\\sqrt{3}" : "sqrt(3)");
    }
    if (expression.Contains("cot(π/3)"))
    {
        /*
        公式:cot(π/3) = √3/3
        证明:我们知道tan(π/3) = √3。余切cotθ是正切tanθ的倒数,即cotθ = 1/tanθ。因此,cot(π/3) = 1/tan(π/3) = 1/√3。
        */
        ret = ret.Replace("cot(π/3)", isLatexFormat ? "\\frac{\\sqrt{3}}{3}" : "sqrt(3)/3");
    }
    return ret;
}

// 将函数定义为字符串
string functionString = "cos(x)"; // 将函数解析为符号表达式
SymbolicExpression function = SymbolicExpression.Parse(functionString);
// 代入x=π/3到函数
string x_value = "π/3";
SymbolicExpression val1 = SymbolicExpression.Parse(x_value); 
SymbolicExpression x = SymbolicExpression.Parse("x"); 
SymbolicExpression y = function.Substitute(x, val1); 
string ret_y = calculate_trigonometric_functions(y.ToString(), true);
// 关于x符号化的微分函数
SymbolicExpression derivative = function.Differentiate("x");
// 代入x=π/3到微分函数
SymbolicExpression result = derivative.Substitute(x, val1); 
string ret = result.ToString(); 
if (ret.Contains("sin(π/3)"))
{
    // sin(π/3) = √3/2
    ret = ret.Replace("sin(π/3)", "\\sin \\frac{\\pi}{3}") + "=" + calculate_trigonometric_functions(ret, true);
}
if (ret.Contains("cos(π/3)"))
{
    // cos(π/3) = 1/2
    ret = ret.Replace("cos(π/3)", "\\cos \\frac{\\pi}{3}") + "=" + calculate_trigonometric_functions(ret, true);
}
if (ret.Contains("tan(π/3)"))
{
    // tan(π/3) = √3
    ret = ret.Replace("tan(π/3)", "\\tan \\frac{\\pi}{3}") + "=" + calculate_trigonometric_functions(ret, true);
}
if (ret.Contains("cot(π/3)"))
{
    // cot(π/3) = √3/3
    ret = ret.Replace("cot(π/3)", "\\cot \\frac{\\pi}{3}") + "=" + calculate_trigonometric_functions(ret, true);
}
string latexExpr0 = ConvertToLatex(functionString);
string latexExpr1 = ConvertToLatex(derivative.ToString());//将求解结果函数和值写入Tex文件
string filePath = "derivative_tangents_normals.tex"; // 文件路径 
StringBuilder sb = new StringBuilder(500);
string latexHead = @"\documentclass{article}
\usepackage{amsmath,amssymb,amsfonts}
\usepackage{CJKutf8}
\begin{document}
	\begin{CJK}{UTF8}{gkai}%正文放在此行下与\end{CJK}之间就行
";
string value = x_value.Replace("π","\\pi");
string[] values = value.Split("/");
value = $"\\frac{{{values[0]}}}{{{values[1]}}}";
sb.Append(latexHead);
sb.Append("\r\n");
sb.Append("求曲线$y=" + latexExpr0 + $"$上点$({value},{ret_y})$处的切线方程和法线方程。\r\n");
sb.Append("\r\n");
sb.Append($"解:$y'|_{{x={value}}}=({latexExpr1})|_{{x={value}}}={ret}$,\r\n");
sb.Append("\r\n");
sb.Append($"曲线在点$({value},{ret_y})$处的切线方程为:\r\n");
sb.Append("\r\n");
string tangentsFunction = "y + result * (x - x_value)"; // 将切线函数解析为符号表达式
SymbolicExpression tangents = SymbolicExpression.Parse(tangentsFunction);
SymbolicExpression y0 = SymbolicExpression.Parse("y");
SymbolicExpression result0 = SymbolicExpression.Parse("result");
SymbolicExpression x_value0 = SymbolicExpression.Parse("x_value");
SymbolicExpression tangentsExpression = tangents.Substitute(y0, y).Substitute(result0, result).Substitute(x_value0, x_value);
ret = calculate_trigonometric_functions(tangentsExpression.ToString(), false);
tangentsExpression = SymbolicExpression.Parse(ret);
sb.Append($"$y={tangentsExpression.ToLaTeX()}$,\r\n"); 
sb.Append("\r\n");
sb.Append($"曲线在点$({value},{ret_y})$处的法线方程为:\r\n");
sb.Append("\r\n");
string normalsFunction = "y - result ^ -1 * (x - x_value)"; // 将切线函数解析为符号表达式
SymbolicExpression normals = SymbolicExpression.Parse(normalsFunction);
SymbolicExpression normalsExpression = normals.Substitute(y0, y).Substitute(result0, result).Substitute(x_value0, x_value);
ret = calculate_trigonometric_functions(normalsExpression.ToString(), false);
normalsExpression = SymbolicExpression.Parse(ret);
sb.Append($"$y={normalsExpression.ToLaTeX()}$。\r\n");
string latexTail = @"
\end{CJK}
\end{document}";
sb.Append(latexTail);
string content = sb.ToString(); // 要写入的文本内容 
Encoding utf8bom = new UTF8Encoding(true);
File.WriteAllText(filePath, content, utf8bom);

derivative_tangents_normals.tex文件内容:

xml 复制代码
\documentclass{article}
\usepackage{amsmath,amssymb,amsfonts}
\usepackage{CJKutf8}
\begin{document}
	\begin{CJK}{UTF8}{gkai}%正文放在此行下与\end{CJK}之间就行

	求曲线$y=\cos x$上点$(\frac{\pi}{3},\frac{1}{2})$处的切线方程和法线方程。
	
	解:$y'|_{x=\frac{\pi}{3}}=(-\sin x)|_{x=\frac{\pi}{3}}=-\frac{\sqrt{3}}{2}$,
	
	故曲线在点$(\frac{\pi}{3},\frac{1}{2})$处的切线方程为:

	$y=\frac{1}{2} - \frac{1}{2}\sqrt{3}\left(-\frac{\pi}{3} + x\right)$,

	曲线在点$(\frac{\pi}{3},\frac{1}{2})$处的法线方程为:

	$y=\frac{1}{2} + \frac{-\frac{\pi}{3} + x}{2\sqrt{3}}$。

\end{CJK}
\end{document}
相关推荐
就爱学编程4 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
Oneforlove_twoforjob27 分钟前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
emoji11111127 分钟前
前端对页面数据进行缓存
开发语言·前端·javascript
每天都要学信号38 分钟前
Python(第一天)
开发语言·python
TENET信条39 分钟前
day53 第十一章:图论part04
开发语言·c#·图论
生信圆桌1 小时前
【生信圆桌x教程系列】如何安装 seurat V5版本R包,最详细安装手册
开发语言·r语言
IT猿手1 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解TP1-TP10及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·深度学习·算法·机器学习·matlab·多目标算法
单片机学习之路1 小时前
【C语言】结构
c语言·开发语言·stm32·单片机·51单片机
蜗牛hb1 小时前
VMware Workstation虚拟机网络模式
开发语言·学习·php
汤姆和杰瑞在瑞士吃糯米粑粑1 小时前
【C++学习篇】AVL树
开发语言·c++·学习