use super::pgfdim::{self as d, Decline, R};
use crate::Engine;
use crate::cmd::Cmd;
use crate::hash::CsId;
use crate::token::Token;
const PT: i32 = 65536;
type Binary<'a> = fn(&mut Fx<'a>, &[u8], &[u8]) -> R<Vec<u8>>;
fn pt(n: i32) -> i32 {
n * PT
}
pub struct Fx<'a> {
pub e: &'a Engine,
pub rad: bool,
pub seed: Option<i64>,
pub loop_temp: Option<i64>,
pub last_cs: Option<CsId>,
name: Vec<u8>,
}
fn plain_text(e: &Engine, cs: CsId) -> Option<Vec<u8>> {
let m = e.eqtb.meaning(cs);
if m.cmd != Cmd::Call {
return None;
}
let mac = m.mac.as_ref()?;
if mac.tokens.first() != Some(&Token::END_MATCH) {
return None;
}
let mut out = Vec::with_capacity(mac.tokens.len());
for &t in &mac.tokens[1..] {
if t.is_cs() || t.cmd_code() != Cmd::OtherChar as u32 || t.chr() > 0x7F {
return None;
}
out.push(t.chr() as u8);
}
Some(out)
}
pub fn split_args(s: &[u8]) -> Option<Vec<&[u8]>> {
let mut out = Vec::new();
let mut i = 0;
while i < s.len() {
if s[i] == b'{' {
let mut depth = 0;
let start = i + 1;
loop {
match s.get(i)? {
b'{' => depth += 1,
b'}' => {
depth -= 1;
if depth == 0 {
break;
}
}
_ => {}
}
i += 1;
}
out.push(&s[start..i]);
i += 1;
} else if s[i] == b'}' {
return None;
} else {
out.push(&s[i..i + 1]);
i += 1;
}
}
Some(out)
}
fn plain(s: &[u8]) -> R<&[u8]> {
if s.iter().any(|&c| c == b'{' || c == b'}') {
return Err(Decline);
}
Ok(s)
}
fn scan(s: &[u8]) -> R<i32> {
d::scan_pt(plain(s)?)
}
fn times_thousand(t: &[u8]) -> R<Vec<u8>> {
let (int, frac) = d::split_point(t);
let mut f = frac.to_vec();
f.extend_from_slice(b"000");
let mut out = int.to_vec();
out.extend_from_slice(&f[..3]);
out.push(b'.');
out.extend_from_slice(&f[3..]);
Ok(out)
}
impl<'a> Fx<'a> {
pub fn new(e: &'a Engine, rad: bool) -> Fx<'a> {
Fx {
e,
rad,
seed: None,
loop_temp: None,
last_cs: None,
name: Vec::new(),
}
}
fn table(&mut self, prefix: &str, n: &[u8]) -> R<Vec<u8>> {
self.name.clear();
self.name.extend_from_slice(prefix.as_bytes());
self.name.extend_from_slice(n);
let cs = self.e.hash.lookup(&self.name).ok_or(Decline)?;
let text = plain_text(self.e, cs).ok_or(Decline)?;
self.last_cs = Some(cs);
Ok(text)
}
fn table_n(&mut self, prefix: &str, n: i64) -> R<Vec<u8>> {
self.table(prefix, n.to_string().as_bytes())
}
pub fn call(&mut self, name: &[u8], args: &[&[u8]]) -> Option<R<Vec<u8>>> {
let one = |f: fn(&mut Fx<'a>, &[u8]) -> R<Vec<u8>>, fx: &mut Fx<'a>| match args {
[a] => f(fx, a),
_ => Err(Decline),
};
let two = |f: Binary<'a>, fx: &mut Fx<'a>| match args {
[a, b] => f(fx, a, b),
_ => Err(Decline),
};
let zero = |v: &[u8]| match args {
[] => Ok(v.to_vec()),
_ => Err(Decline),
};
Some(match name {
b"add" => two(|_, a, b| d::add(plain(a)?, plain(b)?), self),
b"subtract" => two(|_, a, b| d::subtract(plain(a)?, plain(b)?), self),
b"multiply" => two(|_, a, b| d::multiply(plain(a)?, plain(b)?), self),
b"divide" => two(|_, a, b| d::divide(plain(a)?, plain(b)?), self),
b"neg" => one(|_, a| d::neg(plain(a)?), self),
b"reciprocal" => one(|_, a| d::reciprocal(plain(a)?), self),
b"pow" => two(Fx::pow, self),
b"sin" => one(Fx::sin, self),
b"cos" => one(Fx::cos, self),
b"tan" => one(Fx::tan, self),
b"atan" => one(Fx::atan, self),
b"atan2" => two(Fx::atan2, self),
b"asin" => one(Fx::asin, self),
b"acos" => one(Fx::acos, self),
b"deg" => one(Fx::deg, self),
b"rad" => one(Fx::rad, self),
b"veclen" => two(Fx::veclen, self),
b"sqrt" => one(Fx::sqrt, self),
b"abs" => one(Fx::abs, self),
b"max" => one(|fx, a| fx.min_max(a, true), self),
b"min" => one(|fx, a| fx.min_max(a, false), self),
b"mod" => two(Fx::modulo, self),
b"round" => one(Fx::round, self),
b"floor" => one(Fx::floor, self),
b"ceil" => one(Fx::ceil, self),
b"exp" => one(Fx::exp, self),
b"ln" => one(Fx::ln, self),
b"factorial" => one(Fx::factorial, self),
b"pi" => zero(b"3.141592654"),
b"e" => zero(b"2.718281828"),
b"true" => zero(b"1"),
b"false" => zero(b"0"),
b"rnd" => match args {
[] => self.rnd(),
_ => Err(Decline),
},
b"rand" => match args {
[] => self.rand(),
_ => Err(Decline),
},
b"greater" => two(|_, a, b| Ok(bool_str(scan(a)? > scan(b)?)), self),
b"less" => two(|_, a, b| Ok(bool_str(scan(a)? < scan(b)?)), self),
b"equal" => two(|_, a, b| Ok(bool_str(scan(a)? == scan(b)?)), self),
b"notequal" => two(|_, a, b| Ok(bool_str(scan(a)? != scan(b)?)), self),
b"notless" => two(|_, a, b| Ok(bool_str(scan(a)? >= scan(b)?)), self),
b"notgreater" => two(|_, a, b| Ok(bool_str(scan(a)? <= scan(b)?)), self),
b"and" => two(|_, a, b| Ok(bool_str(scan(a)? != 0 && scan(b)? != 0)), self),
b"or" => two(
|_, a, b| Ok(bool_str(scan(a)? != 0 || scan(b)? != 0)),
self,
),
b"not" => one(|_, a| Ok(bool_str(scan(a)? == 0)), self),
b"ifthenelse" => match args {
[c, a, b] => scan(c).map(|v| if v == 0 { b.to_vec() } else { a.to_vec() }),
_ => Err(Decline),
},
_ => return None,
})
}
fn rad_to_deg(x: i32) -> R<i32> {
d::scan_factor(b"57.29577", x)
}
fn deg_to_rad(x: i32) -> R<i32> {
d::ddiv(d::scan_factor(b"3.14159", x)?, 180)
}
pub fn deg(&mut self, a: &[u8]) -> R<Vec<u8>> {
d::returnone(Fx::rad_to_deg(scan(a)?)?)
}
pub fn rad(&mut self, a: &[u8]) -> R<Vec<u8>> {
d::returnone(Fx::deg_to_rad(scan(a)?)?)
}
fn cosine(&mut self, a: &[u8], shift: bool) -> R<Vec<u8>> {
let mut x = scan(a)?;
if self.rad {
x = Fx::rad_to_deg(x)?;
}
if shift {
x = d::adv(x, pt(-90))?;
}
let mut c = d::int_part(x);
c = d::tex_divide(c, 360)?;
c = d::tex_multiply(c, -360)?;
x = d::adv(x, d::count_pt(c)?)?;
if x < 0 {
x = -x;
}
if x >= pt(180) {
x = -x;
x = d::adv(x, pt(360))?;
}
let (mut c, xa) = d::int_and_fraction(x)?;
if xa == 0 {
x = d::scan_pt(&self.table_n("pgfmath@cos@", c)?)?;
} else {
x = -xa;
x = d::adv(x, PT)?;
x = d::scan_factor(&self.table_n("pgfmath@cos@", c)?, x)?;
c += 1;
if c == 181 {
c = 179;
}
let t = self.table_n("pgfmath@cos@", c)?;
x = d::adv(x, d::scan_factor(&t, xa)?)?;
}
d::returnone(x)
}
pub fn sin(&mut self, a: &[u8]) -> R<Vec<u8>> {
self.cosine(a, true)
}
pub fn cos(&mut self, a: &[u8]) -> R<Vec<u8>> {
self.cosine(a, false)
}
pub fn tan(&mut self, a: &[u8]) -> R<Vec<u8>> {
let a = plain(a)?;
let c = self.cos(a)?;
let t = d::reciprocal(&c)?;
let s = self.sin(a)?;
let x = d::scan_pt(&s)?;
d::returnone(d::scan_factor(&t, x)?)
}
fn lookup(&mut self, x: i32, prefix: &str, size: i64) -> R<i32> {
let s = d::print(x);
let (int, frac) = d::split_point(&s);
let int = int.to_vec();
let mut x = d::scan_pt(&self.table(prefix, &int)?)?;
let c = d::scan_int(&int)? + 1;
if c < size {
let mut ya = d::scan_pt(&self.table_n(prefix, c)?)?;
ya = d::adv(ya, -x)?;
let mut f = b"0.".to_vec();
f.extend_from_slice(frac);
x = d::adv(x, d::scan_factor(&f, ya)?)?;
}
Ok(x)
}
pub fn atan(&mut self, a: &[u8]) -> R<Vec<u8>> {
let mut x = scan(a)?;
let xa = x;
if x < 0 {
x = -x;
}
let xb = x;
if x > PT {
let r = d::reciprocal(&d::print(x))?;
x = d::scan_pt(&r)?;
}
x = d::scan_pt(×_thousand(&d::print(x))?)?;
x = self.lookup(x, "pgfmath@atan@", 1001)?;
if xb > PT {
x = -x;
x = d::adv(x, pt(90))?;
}
if xa < 0 {
x = -x;
}
if self.rad {
x = Fx::deg_to_rad(x)?;
}
d::returnone(x)
}
fn arc(&mut self, a: &[u8], sine: bool) -> R<Vec<u8>> {
let x = scan(a)?;
let xa = x;
let mut x = d::scan_pt(×_thousand(&d::print(x))?)?;
if x < 0 {
x = -x;
}
x = self.lookup(x, "pgfmath@acos@", 1001)?;
if sine {
x = -x;
x = d::adv(x, pt(90))?;
if xa < 0 {
x = -x;
}
} else if xa < 0 {
x = -x;
x = d::adv(x, pt(180))?;
}
if self.rad {
x = Fx::deg_to_rad(x)?;
}
d::returnone(x)
}
pub fn asin(&mut self, a: &[u8]) -> R<Vec<u8>> {
self.arc(a, true)
}
pub fn acos(&mut self, a: &[u8]) -> R<Vec<u8>> {
self.arc(a, false)
}
pub fn atan2(&mut self, a: &[u8], b: &[u8]) -> R<Vec<u8>> {
let (a, b) = (plain(a)?, plain(b)?);
let rad = std::mem::replace(&mut self.rad, false);
let r = self.atan2_deg(a, b);
self.rad = rad;
let mut x = r?;
if rad {
x = Fx::deg_to_rad(x)?;
}
d::returnone(x)
}
fn atan2_deg(&mut self, a: &[u8], b: &[u8]) -> R<i32> {
let mut y = d::scan_pt(a)?;
if y < 0 {
y = -y;
}
let small = d::scan_pt(b"0.001")?;
let mut x;
if y < small {
x = if d::scan_pt(b)? < 0 {
pt(180)
} else if d::scan_pt(b)? > 0 {
0
} else if d::scan_pt(a)? < 0 {
pt(-90)
} else {
pt(90)
};
} else {
let ta = self.abs(a)?;
let tb = self.abs(b)?;
if d::scan_pt(&ta)? > d::scan_pt(&tb)? {
let r = d::divide(b, &ta)?;
let r = self.atan(&r)?;
x = pt(90);
let mut m = vec![b'-'];
m.extend_from_slice(&r);
x = d::adv(x, d::scan_pt(&m)?)?;
} else {
let r = d::divide(&ta, b)?;
let r = self.atan(&r)?;
x = d::scan_pt(&r)?;
if d::scan_pt(b)? < 0 {
x = d::adv(x, pt(180))?;
}
}
if d::scan_pt(a)? < 0 {
x = -x;
}
}
Ok(x)
}
pub fn veclen(&mut self, a: &[u8], b: &[u8]) -> R<Vec<u8>> {
let mut x = scan(a)?;
let mut y = scan(b)?;
if x < 0 {
x = -x;
}
if y < 0 {
y = -y;
}
if x == 0 {
x = y;
} else if y != 0 {
if x > y {
std::mem::swap(&mut x, &mut y);
}
let c: i64 = if y > pt(10000) {
1500
} else if y > pt(1000) {
150
} else if y > pt(100) {
50
} else {
1
};
x = d::ddiv(x, c)?;
y = d::ddiv(y, c)?;
let r = d::reciprocal(&d::print(y))?;
x = d::scan_factor(&r, x)?;
let xa = d::scan_factor(&d::print(x), x)?;
let temp = d::print(xa);
x = d::scan_factor(b"-0.01019210944", xa)?;
x = d::adv(x, d::scan_pt(b"0.04453994279")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, d::scan_pt(b"-0.1195159052")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, d::scan_pt(b"0.4993615349")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, d::scan_pt(b"1.000012594")?)?;
if y < 0 {
y = -y;
}
x = d::scan_factor(&d::print(y), x)?;
x = d::dmul(x, c)?;
}
d::returnone(x)
}
pub fn min_max(&mut self, a: &[u8], max: bool) -> R<Vec<u8>> {
let mut x = pt(if max { -16383 } else { 16383 });
for item in split_args(a).ok_or(Decline)? {
if item.is_empty() {
return Err(Decline); }
let v = scan(item)?;
if (max && v > x) || (!max && v < x) {
x = v;
}
}
d::returnone(x)
}
pub fn abs(&mut self, a: &[u8]) -> R<Vec<u8>> {
let mut x = scan(a)?;
if x < 0 {
x = -x;
}
d::returnone(x)
}
pub fn modulo(&mut self, a: &[u8], b: &[u8]) -> R<Vec<u8>> {
let xa = scan(a)?;
let mut xb = scan(b)?;
let mut x = xa;
let c = d::tex_divide(i64::from(xa), i64::from(xb))?;
xb = d::dmul(xb, c)?;
x = d::adv(x, -xb)?;
d::returnone(x)
}
pub fn exp(&mut self, a: &[u8]) -> R<Vec<u8>> {
let mut xc = scan(a)?;
let yc = xc;
let mut x;
if xc < pt(-9) {
x = 1;
} else {
if xc < 0 {
xc = -xc;
}
x = PT;
let mut xa = PT;
let mut xb = x;
let factor = d::print(xc);
let mut counter: i64 = 1;
loop {
xa = d::ddiv(xa, counter)?;
xa = d::scan_factor(&factor, xa)?;
x = d::adv(x, xa)?;
if x == xb {
break;
}
xb = x;
counter += 1;
self.loop_temp = Some(counter);
if counter > 10_000 {
return Err(Decline);
}
}
if yc < 0 {
let r = d::reciprocal(&d::print(x))?;
x = d::scan_pt(&r)?;
}
}
d::returnone(x)
}
pub fn ln(&mut self, a: &[u8]) -> R<Vec<u8>> {
let mut x = scan(a)?;
if x <= 0 {
return Err(Decline); }
let p = |s: &[u8]| d::scan_pt(s);
let (scale, c): (i64, i64) = if x > pt(2) {
if x < pt(128) {
if x < pt(8) {
if x < pt(4) { (-2, 1) } else { (-4, 2) }
} else if x < pt(32) {
if x < pt(16) { (-8, 3) } else { (-16, 4) }
} else if x < pt(64) {
(-32, 5)
} else {
(-64, 6)
}
} else if x < pt(2048) {
if x < pt(512) {
if x < pt(256) { (-128, 7) } else { (-256, 8) }
} else if x < pt(1024) {
(-512, 9)
} else {
(-1024, 10)
}
} else if x < pt(8192) {
if x < pt(4096) {
(-2048, 11)
} else {
(-4096, 12)
}
} else {
(-8192, 13)
}
} else if x < PT {
if x > p(b"0.0078125")? {
if x > p(b"0.125")? {
if x > p(b"0.5")? { (2, -1) } else { (4, -2) }
} else if x > p(b"0.03125")? {
if x > p(b"0.0625")? { (8, -3) } else { (16, -4) }
} else if x > p(b"0.015625")? {
(32, -5)
} else {
(64, -6)
}
} else if x > p(b"0.00048828125")? {
if x > p(b"0.001953125")? {
if x > p(b"0.00390625")? {
(128, -7)
} else {
(256, -8)
}
} else if x > p(b"0.0009765625")? {
(512, -9)
} else {
(1024, -10)
}
} else if x > p(b"0.0001220703125")? {
if x > p(b"0.0002441406256")? {
(2048, -11)
} else {
(4096, -12)
}
} else {
(8192, -13)
}
} else {
(1, 0)
};
if scale < 0 {
x = d::ddiv(x, -scale)?;
} else if scale > 1 {
x = d::dmul(x, scale)?;
}
let temp = d::print(x);
x = d::scan_factor(b"0.04300521312", x)?;
x = d::adv(x, p(b"-.4025153233")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, p(b"1.589480044")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, p(b"-3.489886985")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, p(b"5.047861502")?)?;
x = d::scan_factor(&temp, x)?;
x = d::adv(x, p(b"-2.787927935")?)?;
x = d::adv(x, d::count_pt(c)?)?;
x = d::scan_factor(b"0.6931471806", x)?;
d::returnone(x)
}
pub fn pow(&mut self, a: &[u8], b: &[u8]) -> R<Vec<u8>> {
let (a, b) = (plain(a)?, plain(b)?);
let mut xa = d::scan_pt(a)?;
let xb = d::scan_pt(b)?;
let x = if xa == 0 {
if xb == 0 { PT } else { 0 }
} else {
let (mut n, frac) = d::int_and_fraction(xb)?;
if n < 0 {
n = -n;
xa = d::scan_pt(&d::reciprocal(a)?)?;
}
if frac == 0 {
let mut x = PT;
let mut counter = 1;
while n > 0 {
if n % 2 != 0 {
x = d::scan_factor(&d::print(x), xa)?;
}
if n > 1 {
xa = d::scan_factor(&d::print(xa), xa)?;
}
n /= 2;
counter += 1;
self.loop_temp = Some(counter);
}
x
} else {
let r = self.ln(a)?;
let mut x = d::scan_pt(&r)?;
x = d::scan_factor(&d::print(xb), x)?;
let r = self.exp(&d::print(x))?;
d::scan_pt(&r)?
}
};
d::returnone(x)
}
pub fn sqrt(&mut self, a: &[u8]) -> R<Vec<u8>> {
let x = scan(a)?;
if x < 0 {
return Err(Decline);
}
let (zeros, mut target): (&[u8], i64) = if x < pt(10) {
(b"0", 1)
} else if x < pt(100) {
(b"", 1)
} else if x < pt(1000) {
(b"0", 2)
} else if x < pt(10000) {
(b"", 2)
} else {
(b"0", 3)
};
let mut temp = zeros.to_vec();
temp.extend_from_slice(&d::print(x));
let (int, frac) = d::split_point(&temp);
let mut digits: Vec<i64> = int
.iter()
.chain(frac)
.map(|&c| i64::from(c - b'0'))
.collect();
digits.reverse();
let mut next = || digits.pop();
let d1 = next().ok_or(Decline)?;
let d2 = next().ok_or(Decline)?;
let countb = d1 * 10 + d2;
let first = match countb {
81.. => 9,
64.. => 8,
49.. => 7,
36.. => 6,
25.. => 5,
16.. => 4,
9.. => 3,
4.. => 2,
1.. => 1,
_ => 0,
};
let mut root = first.to_string().into_bytes();
let mut special: i64 = first;
let mut remainder: i64 = countb - first * first;
loop {
let (r1, r2) = (next(), next());
remainder = match (r1, r2) {
(None, _) => d::tex_multiply(remainder, 100)?,
(Some(a), None) => d::cadv(d::tex_multiply(remainder, 100)?, a * 10)?,
(Some(a), Some(b)) => d::cadv(d::tex_multiply(remainder, 100)?, a * 10 + b)?,
};
let counta = d::tex_multiply(special, 20)?;
let mut countb = d::cadv(d::tex_multiply(counta, 6)?, 36)?;
let countc = d::tex_multiply(counta, 2)?;
let digit;
if countb > remainder {
countb = countb - countc - 20;
if countb > remainder {
countb = countb - countc - 12;
if countb > remainder {
countb = countb - counta - 3;
digit = if countb > remainder { 0 } else { 1 };
} else {
countb = countb + counta + 5;
digit = if countb > remainder { 2 } else { 3 };
}
} else {
countb = countb + counta + 9;
digit = if countb > remainder { 4 } else { 5 };
}
} else {
countb = countb + countc + 28;
if countb > remainder {
countb = countb - counta - 15;
digit = if countb > remainder { 6 } else { 7 };
} else {
countb = countb + counta + 17;
digit = if countb > remainder { 8 } else { 9 };
}
}
special = d::cadv(d::tex_multiply(special, 10)?, digit)?;
let c = d::tex_multiply(counta + digit, -digit)?;
remainder = d::cadv(c, remainder)?;
target -= 1;
if target == 0 {
root.push(b'.');
}
root.push(b'0' + digit as u8);
if target == -4 {
break;
}
}
Ok(root)
}
pub fn factorial(&mut self, a: &[u8]) -> R<Vec<u8>> {
let (mut c, _) = d::scan_int_prefix(plain(a)?)?;
let mut x = PT;
let mut counter = 1;
while c >= 2 {
x = d::dmul(x, c)?;
c -= 1;
counter += 1;
self.loop_temp = Some(counter);
}
Ok(d::print(x))
}
pub fn scientific(&mut self, mant: &[u8], exp: i64) -> R<Vec<u8>> {
let mant = plain(mant)?;
let x = d::scan_pt(mant)?;
let (sign, mut temp): (&[u8], Vec<u8>) = if x < 0 {
(b"-", mant.get(1..).ok_or(Decline)?.to_vec())
} else {
(b"+", mant.to_vec())
};
if !mant.contains(&b'.') {
temp.extend_from_slice(b".0");
}
temp.extend_from_slice(b"00000000000");
let (int, frac) = d::split_point(&temp);
if int.is_empty() || frac.len() < 10 {
return Err(Decline);
}
let (mant_a, mant_b) = (&frac[..5], &frac[5..10]);
let x = if exp < -4 {
0
} else {
let n = exp.abs();
let p = self.pow(b"10", n.to_string().as_bytes())?;
let factor = d::scan_int_prefix(&p)?.0;
if exp < 0 {
let mut t = int.to_vec();
t.push(b'.');
t.extend_from_slice(mant_a);
d::ddiv(d::scan_pt(&t)?, factor)?
} else {
let mut counta = d::scan_int(int)?;
let mut countb = d::scan_int(mant_a)?;
counta = d::tex_multiply(counta, factor)?;
countb = d::tex_multiply(countb, factor)?;
let mut countc = countb;
countb = d::tex_divide(countb, 100_000)?;
counta = d::cadv(counta, countb)?;
countb = d::tex_multiply(countb, 100_000)?;
countc = d::cadv(countc, -countb)?;
countb = d::scan_int(mant_b)?;
countb = d::tex_multiply(countb, factor)?;
countb = d::tex_divide(countb, 100_000)?;
countc = d::cadv(countc, countb)?;
countc = d::cadv(countc, 100_000)?;
let c = countc.to_string().into_bytes();
let mut t = sign.to_vec();
t.extend_from_slice(counta.to_string().as_bytes());
t.push(b'.');
t.extend_from_slice(c.get(1..).ok_or(Decline)?);
d::scan_pt(&t)?
}
};
d::returnone(x)
}
pub fn round(&mut self, a: &[u8]) -> R<Vec<u8>> {
let x = scan(a)?;
let (mut c, xa) = d::int_and_fraction(x)?;
if xa >= PT / 2 {
c += if x < 0 { -1 } else { 1 };
}
d::returnone(d::scan_pt(c.to_string().as_bytes())?)
}
pub fn floor(&mut self, a: &[u8]) -> R<Vec<u8>> {
let x = scan(a)?;
let (mut c, rem) = d::int_and_fraction(x)?;
if x < 0 && rem > 0 {
c -= 1;
}
d::returnone(d::count_pt(c)?)
}
pub fn ceil(&mut self, a: &[u8]) -> R<Vec<u8>> {
let x = scan(a)?;
let c = d::int_part(x);
let y = d::adv(x, -d::count_pt(c)?)?;
let mut x = d::count_pt(c)?;
if y > 0 {
x = d::adv(x, PT)?;
}
d::returnone(x)
}
fn next_random(&mut self) -> R<i64> {
let z = match self.seed {
Some(z) => z,
None => {
let cs = self.e.hash.lookup(b"pgfmath@rnd@z").ok_or(Decline)?;
let text = plain_text(self.e, cs).ok_or(Decline)?;
d::scan_int(&text)?
}
};
let (m, a, r, q) = (2_147_483_647, 69621, 23902, 30845);
let mut counta = z;
let mut countb = z;
counta = d::tex_divide(counta, q)?;
counta = d::tex_multiply(counta, -q)?;
counta = d::cadv(counta, countb)?;
counta = d::tex_multiply(counta, a)?;
countb = d::tex_divide(countb, q)?;
countb = d::tex_multiply(countb, r)?;
counta = d::cadv(counta, -countb)?;
if counta < 0 {
counta = d::cadv(counta, m)?;
}
self.seed = Some(counta);
Ok(counta)
}
pub fn rnd(&mut self) -> R<Vec<u8>> {
let counta = self.next_random()?;
let mut countb = d::tex_divide(counta, 100_001)?;
countb = d::tex_multiply(countb, -100_001)?;
countb = d::cadv(countb, counta)?;
countb = d::cadv(countb, 1_000_000)?;
let s = countb.to_string().into_bytes();
if s.len() < 3 {
return Err(Decline);
}
let mut t = vec![s[1], b'.'];
t.extend_from_slice(&s[2..]);
d::returnone(d::scan_pt(&t)?)
}
pub fn rand(&mut self) -> R<Vec<u8>> {
let counta = self.next_random()?;
let mut countb = d::tex_divide(counta, 200_001)?;
countb = d::tex_multiply(countb, -200_001)?;
countb = d::cadv(countb, counta)?;
countb = d::cadv(countb, -100_000)?;
countb = d::cadv(countb, if countb < 0 { -1_000_000 } else { 1_000_000 })?;
let s = countb.to_string().into_bytes();
if s.len() < 4 {
return Err(Decline);
}
let t = if s[0] == b'-' {
let mut t = vec![b'-', s[2], b'.'];
t.extend_from_slice(&s[3..]);
t
} else {
let mut t = vec![s[1], b'.', s[2]];
t.extend_from_slice(&s[3..]);
t
};
d::returnone(d::scan_pt(&t)?)
}
}
fn bool_str(b: bool) -> Vec<u8> {
vec![if b { b'1' } else { b'0' }]
}