mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 05:34:14 +00:00
Merge remote-tracking branch 'origin/master' into docs-markup
This commit is contained in:
commit
21acc56f24
8 changed files with 169 additions and 33 deletions
18
Makefile
18
Makefile
|
@ -50,18 +50,18 @@ htmldoc:
|
|||
$(ASCIIDOCTOR) $(HTMLFLAGS) $(srcdir)/docs/rink-dates.5.adoc
|
||||
|
||||
installbin:
|
||||
$(INSTALL) -Dm 0755 target/release/rink -t $(bindir)
|
||||
$(INSTALL) -Dm 0755 target/release/rink $(bindir)
|
||||
|
||||
installman:
|
||||
$(INSTALL) -Dm 0644 build/rink.1 -t $(man1dir)
|
||||
$(INSTALL) -Dm 0644 build/rink.5 -t $(man5dir)
|
||||
$(INSTALL) -Dm 0644 build/rink.7 -t $(man7dir)
|
||||
$(INSTALL) -Dm 0644 build/rink-defs.5 -t $(man5dir)
|
||||
$(INSTALL) -Dm 0644 build/rink-dates.5 -t $(man5dir)
|
||||
$(INSTALL) -Dm 0644 build/rink.1 $(man1dir)
|
||||
$(INSTALL) -Dm 0644 build/rink.5 $(man5dir)
|
||||
$(INSTALL) -Dm 0644 build/rink.7 $(man7dir)
|
||||
$(INSTALL) -Dm 0644 build/rink-defs.5 $(man5dir)
|
||||
$(INSTALL) -Dm 0644 build/rink-dates.5 $(man5dir)
|
||||
|
||||
installfiles:
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/definitions.units -t $(datadir)/rink
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/datepatterns.txt -t $(datadir)/rink
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/currency.units -t $(datadir)/rink
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/definitions.units $(datadir)/rink
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/datepatterns.txt $(datadir)/rink
|
||||
$(INSTALL) -Dm 0644 $(srcdir)/core/currency.units $(datadir)/rink
|
||||
|
||||
install: installbin installman installfiles
|
||||
|
|
|
@ -8,6 +8,9 @@ pub enum Digits {
|
|||
Default,
|
||||
FullInt,
|
||||
Digits(u64),
|
||||
Fraction,
|
||||
Scientific,
|
||||
Engineering,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
|
|
@ -836,6 +836,18 @@ pub fn parse_query(iter: &mut Iter<'_>) -> Query {
|
|||
_ => Digits::FullInt,
|
||||
}
|
||||
}
|
||||
Token::Ident(ref s) if s == "frac" || s == "fraction" || s == "ratio" => {
|
||||
iter.next();
|
||||
Digits::Fraction
|
||||
}
|
||||
Token::Ident(ref s) if s == "sci" || s == "scientific" => {
|
||||
iter.next();
|
||||
Digits::Scientific
|
||||
}
|
||||
Token::Ident(ref s) if s == "eng" || s == "engineering" => {
|
||||
iter.next();
|
||||
Digits::Engineering
|
||||
}
|
||||
_ => Digits::Default,
|
||||
};
|
||||
let base = match iter.peek().cloned().unwrap() {
|
||||
|
|
|
@ -860,8 +860,16 @@ pub(crate) fn eval_query(ctx: &Context, expr: &Query) -> Result<QueryReply, Quer
|
|||
value: parts,
|
||||
})))
|
||||
}
|
||||
Query::Convert(ref top, Conversion::None, base, digits @ Digits::Digits(_))
|
||||
| Query::Convert(ref top, Conversion::None, base, digits @ Digits::FullInt) => {
|
||||
Query::Convert(
|
||||
ref top,
|
||||
Conversion::None,
|
||||
base,
|
||||
digits @ Digits::Digits(_)
|
||||
| digits @ Digits::FullInt
|
||||
| digits @ Digits::Fraction
|
||||
| digits @ Digits::Scientific
|
||||
| digits @ Digits::Engineering,
|
||||
) => {
|
||||
let top = eval_expr(ctx, top)?;
|
||||
let top = match top {
|
||||
Value::Number(top) => top,
|
||||
|
@ -873,17 +881,14 @@ pub(crate) fn eval_query(ctx: &Context, expr: &Query) -> Result<QueryReply, Quer
|
|||
Digits::Default => unreachable!(),
|
||||
Digits::FullInt => "digits".to_owned(),
|
||||
Digits::Digits(n) => format!("{} digits", n),
|
||||
Digits::Fraction => "fraction".to_owned(),
|
||||
Digits::Scientific => "scientific".to_owned(),
|
||||
Digits::Engineering => "engineering".to_owned(),
|
||||
}
|
||||
)))
|
||||
}
|
||||
};
|
||||
let (exact, approx) = top.numeric_value(base.unwrap_or(10), digits);
|
||||
let parts = NumberParts {
|
||||
raw_value: Some(top.clone()),
|
||||
exact_value: exact,
|
||||
approx_value: approx,
|
||||
..top.to_parts(ctx)
|
||||
};
|
||||
let parts = top.to_parts_digits(ctx, base.unwrap_or(10), digits);
|
||||
Ok(QueryReply::Conversion(Box::new(ConversionReply {
|
||||
value: parts,
|
||||
})))
|
||||
|
@ -1056,9 +1061,15 @@ pub(crate) fn eval_query(ctx: &Context, expr: &Query) -> Result<QueryReply, Quer
|
|||
which, digits
|
||||
)))
|
||||
}
|
||||
Query::Convert(ref _expr, ref which, _base, Digits::FullInt) => Err(QueryError::generic(
|
||||
format!("Conversion to digits of {} is not defined", which),
|
||||
)),
|
||||
Query::Convert(
|
||||
ref _expr,
|
||||
ref which,
|
||||
_base,
|
||||
Digits::FullInt | Digits::Fraction | Digits::Scientific | Digits::Engineering,
|
||||
) => Err(QueryError::generic(format!(
|
||||
"Conversion to digits of {} is not defined",
|
||||
which
|
||||
))),
|
||||
Query::Factorize(ref expr) => {
|
||||
let mut val = None;
|
||||
if let Expr::Unit { ref name } = *expr {
|
||||
|
|
|
@ -123,8 +123,8 @@ impl BigRat {
|
|||
let exact = cursor == zero;
|
||||
let placed_ints = n >= intdigits;
|
||||
let ndigits = match digits {
|
||||
Digits::Default => 6,
|
||||
Digits::FullInt => 1000,
|
||||
Digits::Default | Digits::Scientific | Digits::Engineering => 6,
|
||||
Digits::FullInt | Digits::Fraction => 1000,
|
||||
Digits::Digits(n) => intdigits as i32 + n as i32,
|
||||
};
|
||||
// Conditions for exiting:
|
||||
|
@ -221,11 +221,22 @@ impl BigRat {
|
|||
self * &BigRat::ratio(&absexp, &BigInt::one())
|
||||
};
|
||||
let ten = BigRat::small_ratio(base as i64, 1);
|
||||
let (rational, intdigits) = if rational.abs() == ten {
|
||||
let (mut rational, mut intdigits) = if rational.abs() == ten {
|
||||
(&rational / &ten, intdigits + 1)
|
||||
} else {
|
||||
(rational, intdigits)
|
||||
};
|
||||
|
||||
if digits == Digits::Engineering {
|
||||
let adjust = (intdigits % 3 + 3) % 3;
|
||||
rational = &rational
|
||||
* &BigRat::ratio(
|
||||
&BigInt::from(base as i64).pow(adjust as u32),
|
||||
&BigInt::one(),
|
||||
);
|
||||
intdigits -= adjust;
|
||||
}
|
||||
|
||||
let (is_exact, mut result) = rational.to_digits_impl(base, digits);
|
||||
if !result.contains('.') {
|
||||
result.push('.');
|
||||
|
@ -241,15 +252,19 @@ impl BigRat {
|
|||
return (true, "0".to_owned());
|
||||
}
|
||||
|
||||
if digits == Digits::Fraction {
|
||||
return (true, format!("{}", self));
|
||||
}
|
||||
|
||||
let abs = self.abs();
|
||||
let is_computer_base = base == 2 || base == 8 || base == 16 || base == 32;
|
||||
let is_computer_integer = is_computer_base && self.denom() == BigInt::one();
|
||||
let can_use_sci = digits == Digits::Default && !is_computer_integer;
|
||||
let can_use_sci =
|
||||
(digits == Digits::Default || digits == Digits::Engineering) && !is_computer_integer;
|
||||
let in_range_for_sci = &abs >= &BigRat::small_ratio(1_000_000_000, 1)
|
||||
|| &abs <= &BigRat::small_ratio(1, 1_000_000_000);
|
||||
|
||||
if can_use_sci
|
||||
&& (&abs >= &BigRat::small_ratio(1_000_000_000, 1)
|
||||
|| &abs <= &BigRat::small_ratio(1, 1_000_000_000))
|
||||
{
|
||||
if digits == Digits::Scientific || can_use_sci && in_range_for_sci {
|
||||
self.to_scientific(base, digits)
|
||||
} else {
|
||||
self.to_digits_impl(base, digits)
|
||||
|
|
|
@ -277,6 +277,14 @@ impl Number {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_pretty_unit(&self, context: &Context) -> Number {
|
||||
let unit = self.pretty_unit(context);
|
||||
Number {
|
||||
value: self.value.clone(),
|
||||
unit,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the units of the number from base units to display
|
||||
/// units, and possibly apply SI prefixes.
|
||||
pub fn prettify(&self, context: &Context) -> Number {
|
||||
|
@ -330,8 +338,16 @@ impl Number {
|
|||
}
|
||||
|
||||
pub fn to_parts(&self, context: &Context) -> NumberParts {
|
||||
let value = self.prettify(context);
|
||||
let (exact, approx) = value.numeric_value(10, Digits::Default);
|
||||
self.to_parts_digits(context, 10, Digits::Default)
|
||||
}
|
||||
|
||||
pub fn to_parts_digits(&self, context: &Context, base: u8, digits: Digits) -> NumberParts {
|
||||
let value = if digits == Digits::Default {
|
||||
self.prettify(context)
|
||||
} else {
|
||||
self.with_pretty_unit(context)
|
||||
};
|
||||
let (exact, approx) = value.numeric_value(base, digits);
|
||||
|
||||
let quantity = context
|
||||
.registry
|
||||
|
|
|
@ -806,3 +806,68 @@ fn test_bytes() {
|
|||
test("100 byte^2", "6400 bit^2 (bit^2)");
|
||||
test("1/byte", "0.125 / bit (bit^-1)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_formats() {
|
||||
test("surveyfoot to digits", "0.[304800609601219202438404876809753619507239014478028956057912115824231648463296926593853187706375412750825501651003302006604013208026416052832105664211328422656845313690627381254762509525019050038100076200152400, period 210]... meter (length)");
|
||||
test("surveyfoot to frac", "1200/3937 meter (length)");
|
||||
test("surveyfoot to sci", "approx. 3.048006e-1 meter (length)");
|
||||
test("foot to frac", "381/1250 meter (length)");
|
||||
test("foot to sci", "3.048e-1 meter (length)");
|
||||
test("1 to frac", "1 (dimensionless)");
|
||||
test("1 to sci", "1.0e0 (dimensionless)");
|
||||
test("1/7 to frac", "1/7 (dimensionless)");
|
||||
test("1/7 to fraction", "1/7 (dimensionless)");
|
||||
test("1/7 to ratio", "1/7 (dimensionless)");
|
||||
test("1/7 to sci", "1.[428571]...e-1 (dimensionless)");
|
||||
test("1/7 to scientific", "1.[428571]...e-1 (dimensionless)");
|
||||
test("0.5 to eng", "0.5 (dimensionless)");
|
||||
test("0.5 to engineering", "0.5 (dimensionless)");
|
||||
|
||||
// engineering
|
||||
test("1e9 to eng", "1.0e9 (dimensionless)");
|
||||
test("1e10 to eng", "10.0e9 (dimensionless)");
|
||||
test("1e11 to eng", "100.0e9 (dimensionless)");
|
||||
test("1e12 to eng", "1.0e12 (dimensionless)");
|
||||
test("1e13 to eng", "10.0e12 (dimensionless)");
|
||||
test("1e14 to eng", "100.0e12 (dimensionless)");
|
||||
test("1e15 to eng", "1.0e15 (dimensionless)");
|
||||
test("1e16 to eng", "10.0e15 (dimensionless)");
|
||||
test("1e17 to eng", "100.0e15 (dimensionless)");
|
||||
|
||||
test("1e-9 to eng", "1.0e-9 (dimensionless)");
|
||||
test("1e-10 to eng", "100.0e-12 (dimensionless)");
|
||||
test("1e-11 to eng", "10.0e-12 (dimensionless)");
|
||||
test("1e-12 to eng", "1.0e-12 (dimensionless)");
|
||||
test("1e-13 to eng", "100.0e-15 (dimensionless)");
|
||||
test("1e-14 to eng", "10.0e-15 (dimensionless)");
|
||||
test("1e-15 to eng", "1.0e-15 (dimensionless)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_to_digit_errors() {
|
||||
test(
|
||||
"egg to digits",
|
||||
"<1 (dimensionless) egg> to digits is not defined",
|
||||
);
|
||||
test(
|
||||
"egg to digits 50",
|
||||
"<1 (dimensionless) egg> to 50 digits is not defined",
|
||||
);
|
||||
test(
|
||||
"egg to frac",
|
||||
"<1 (dimensionless) egg> to fraction is not defined",
|
||||
);
|
||||
test(
|
||||
"egg to sci",
|
||||
"<1 (dimensionless) egg> to scientific is not defined",
|
||||
);
|
||||
test(
|
||||
"egg to eng",
|
||||
"<1 (dimensionless) egg> to engineering is not defined",
|
||||
);
|
||||
test(
|
||||
"now to digits \"US/Pacific\"",
|
||||
"Conversion to digits of US/Pacific is not defined",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -372,8 +372,8 @@ recognized:
|
|||
`bin`, `binary`, `base2`::
|
||||
Base 2.
|
||||
|
||||
Digits modifier
|
||||
^^^^^^^^^^^^^^^
|
||||
Number representation modifiers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
> 2^128 -> digits
|
||||
340282366920938463463374607431768211456 (dimensionless)
|
||||
|
@ -381,6 +381,10 @@ Digits modifier
|
|||
0.[000254000508001016002032004064008128016256032512065024130048260096520193040386080772161544323088646177292354584709169418338836677673355346710693421386842773685547371094742189484378968757937515875031750063500127, period 210]... (dimensionless)
|
||||
> googol -> digits
|
||||
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (dimensionless)
|
||||
> mass of electron -> eng
|
||||
approx. 910.9383e-33 kilogram (mass)
|
||||
> 3 foot -> frac
|
||||
1143/1250 meter (length)
|
||||
|
||||
Digits modifiers are specified with `digits` optionally followed by a
|
||||
number, before the base modifier and before the rest of the
|
||||
|
@ -403,6 +407,16 @@ using a machine-float fallback, because their results cannot be
|
|||
precisely represented as finite rationals. Because of this, asking for
|
||||
many digits of such numbers will also produce unsatisfying results.
|
||||
|
||||
`frac`, `fraction`, `ratio` are all equivalent. They will print
|
||||
the rational fraction that Rink internally represents the number using.
|
||||
|
||||
`sci`, `scientific` will force the use of scientific notation, even for
|
||||
small numbers.
|
||||
|
||||
`eng`, `engineering` are similar to the default format, where it uses
|
||||
scientific notation only for large numbers. However, when it does use
|
||||
scientific notation, it rounds down to every third power.
|
||||
|
||||
Units for
|
||||
^^^^^^^^^
|
||||
|
||||
|
|
Loading…
Reference in a new issue