Skip to content

Instantly share code, notes, and snippets.

@repass
Last active January 19, 2023 19:54
Show Gist options
  • Save repass/a8766d33096fb16d306aea488a757e8e to your computer and use it in GitHub Desktop.
Save repass/a8766d33096fb16d306aea488a757e8e to your computer and use it in GitHub Desktop.
symbolic differentiator for polynomial expressions of one variable
// single variable differentiator
// repass 1/9/23
use std::io;
use std::io::prelude::*;
struct Expr {
coeffecient: f32,
variable: String,
exponent: i32,
}
impl Expr {
fn new(expr: String) -> Expr {
let mut chars = expr.chars().peekable();
let mut coeff = String::new();
let mut var = String::new();
let mut exp = String::new();
let ch = *chars.peek().unwrap() as i32;
if ch == 45 {
// '-'
coeff += &chars.next().unwrap().to_string();
} else if ch > 57 {
// not a number
coeff += &"1".to_string();
} else {
coeff += &chars.next().unwrap().to_string();
}
while chars.peek() != None {
let ch = *chars.peek().unwrap() as i32;
//println!("ch is {:x}", ch);
if ch < 58 {
// ch is a number
coeff += &chars.next().unwrap().to_string();
} else if ch > 97 && ch < 122 {
// ch is a lowercase letter
var += &chars.next().unwrap().to_string();
} else if ch == 94 {
// exponent
let _ = &chars.next();
while chars.peek() != None {
exp += &chars.next().unwrap().to_string();
}
}
}
//println!("coeff is {} var is {} exponent is {}", coeff, var, exp);
if exp == "" {
exp = "1".to_string();
}
let coeffecient = coeff.parse::<f32>().unwrap();
let exponent = exp.parse::<i32>().unwrap();
Expr {
coeffecient,
variable: var,
exponent,
}
}
fn derivative(&self) -> String {
if self.variable == "" {
return "0".to_string();
}
let d_coeffecient = self.coeffecient * self.exponent as f32;
let d_exponent = self.exponent - 1;
if d_exponent == 0 {
return d_coeffecient.to_string();
} else if d_exponent == 1 {
return d_coeffecient.to_string() + &self.variable;
} else {
return d_coeffecient.to_string() + &self.variable + &"^" + &d_exponent.to_string();
}
}
}
fn correctly_formed(s: &str) -> bool {
let chars = s.chars();
let mut var: char = '0';
for ch in chars {
let c = ch as i32;
if c == 43 || c == 45 || c == 46 || c == 94 { // + - . ^
} else if c > 47 && c < 57 { // a number
} else if c > 96 && c < 122 {
// lowercase letter
if var == '0' {
//first encounter of a lowercase letter
var = ch;
} else if var == ch {
} else {
println!("variable {} is not {}", var, ch);
return false;
}
} else {
println!("failing valdiation due to {}", ch);
return false;
}
}
true
}
fn main() {
println!("Enter single variable polynomial expressions to find derivates one per line.");
println!("Example: 3x^4 - 12x^3 + x^2 -12x + 10");
println!("Enter without input to take derivative of last result");
println!("Ctrl^D to exit");
let stdin = io::stdin();
let mut history: String = String::new();
for line in stdin.lock().lines() {
let mut dx: String = String::new();
let mut s = line
.expect("stdin error")
.replace(" ", "")
.replace("-", "+-");
if s == "" {
//println!("assigned history \'{}\' to s", history);
s = history.replace(" ", "").replace("-", "+-");
}
if correctly_formed(&s) {
for expr in s.split('+') {
let expression = Expr::new(expr.to_string());
/* println!(
"expression coeffecient is {} variable is {} and exponent is {}",
expression.coeffecient, expression.variable, expression.exponent
); */
dx += &expression.derivative();
dx += "+";
}
history = dx
.replace("+-", " - ")
.replace("+0+", "")
.trim_matches('+')
.replace("+", " + ")
.trim_end()
.to_string();
println!("{}", history);
} else {
println!("Please use a single variable polynomial");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment