Skip to content

Commit b3b2546

Browse files
authored
Merge pull request #133 from rchillyard/V1_2_10
V1.2.10
2 parents 9ac5204 + 726367a commit b3b2546

File tree

76 files changed

+901
-1139
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+901
-1139
lines changed

.circleci/config.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ jobs:
3939
key: v1-dependencies--{{ checksum "build.sbt" }}
4040

4141
# run tests!
42-
- run: cat /dev/null | sbt test:test
42+
- run:
43+
name: Run tests
44+
command: cat /dev/null | sbt "testOnly * -- -l Slow"

README.md

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ However, if you write the idiomatically correct form:
2929

3030
then _x_ will be a _Number_ with value __exactly__ one half.
3131

32+
Even better is to use the lazy expression mechanism:
33+
34+
val half: Expression = One / 2
35+
half.materialize
36+
3237
You probably want to see some code: so go to the _worksheets_ package and take a look, starting with
3338
NumberWorksheet.sc, Foucault1.sc, Newton.sc, and so on.
3439

@@ -55,27 +60,11 @@ These allow the exact representation of roots, logarithmic numbers, radians, and
5560

5661
Current Version
5762
---------------
58-
The current version is 1.2.5. Here's a summary of what's new since 1.2.1:
59-
60-
* The entire _ExpressionMatchers_ code base has been rewritten (leaving many deprecated methods which need to be cleaned
61-
up):
62-
* The key method for simplifying _Expression_s is _simplify_. This operates recursively by invoking _matchSimpler_
63-
until it encounters a miss, in which case it returns the previous simplified version. There are four phases of
64-
simplification for a _CompositeExpression_:
65-
* _simplifyComponents_
66-
* _simplifyTrivial_
67-
* _simplifyConstant_
68-
* _simplifyComposite_
69-
* _Algebraic_ quantities have been introduced:
70-
* These represent solutions to equations that cannot be represented precisely with one quantity
71-
* _Quadratic_ equations, for example, we can represent the Golden ratio $\phi$ exactly this way.
72-
* _Linear_ equations (these solutions can already be represented, but this is just for completeness)
73-
* The _NthRoot_ (renamed from _Root_) domain has been restructured to be more general.
74-
* In addition to _SquareRoot_ and _CubeRoot_ (which were renamed from the ambiguous _Root2_ and _Root3_), there are
75-
more general roots based on a rational inverse power.
76-
* This _README.md_ file has been improved (including a logo, thanks to Zijie).
77-
* Added Series and PowerSeries
78-
* Fixed CircleCI issues
63+
The current version is 1.2.10. Here's a summary of what's new since 1.2.5:
64+
* A major restructuring where we effectively replaced _ReducedQuadraticRoot_ with _Root_ but where _Root_ is an _Expression_. In order for this to work, we renamed the old _Root_ (a subtype of _Factor_) as _NthRoot_.
65+
* Another subtype of Expression was introduced: _Transcendental_. These are subtypes of AtomicExpression but rather than have a literal value, they define a value and an _ExpressionMonoFunction_ to be applied to that value.
66+
* The _Log_ function is now dyadic and, in a parallel change, the old (natural) _log_ method has been renamed _ln_, allowing for new dyadic _log_ method.
67+
* Additional tests have been introduced, including tests for _Root_ and _Transcendental_, while many other tests have been fixed. The only ignored tests are those that CircleCI objects to.
7968

8069
Sources
8170
-------
@@ -91,6 +80,12 @@ You can also find the 7th printing free online:
9180

9281
[1]: https://archive.org/details/handbookofmathem00abra
9382

83+
Operators
84+
=========
85+
86+
The most important operators are those defined in _Expression.ExpressionOps_.
87+
That's because you should normally be using the (lazy) expressions mechanism for arithmetic expressions.
88+
These are the usual operators, except that the power operator is ∧ (not ^ or **).
9489

9590
Java API
9691
========
@@ -189,7 +184,7 @@ It's probably the simplest just to include:
189184
import Rational._
190185

191186
_Doubles_ are where the trickiest conversions apply.
192-
Writing something like _Number(3.1415927)_ will result in a _FuzzyNumber_ with error bounds of 5 * 10^-7.
187+
Writing something like _Number(3.1415927)_ will result in a _FuzzyNumber_ with error bounds of 5 * 10-7.
193188
To be consistent with the _String_ representation, _Number(1.25)_ will result in an _ExactNumber_ represented internally
194189
by a _Rational_ of 5/4.
195190
However, if you want to force a number like 3.1415927 to be exact, then you will need to write
@@ -278,7 +273,7 @@ to build a _Mill_.
278273

279274
Some of the operators of _Mill_ are as follows:
280275

281-
^: Power
276+
: Power (also ^)
282277
+: Add
283278
-: Subtract
284279
*: Multiply (also ×)
@@ -406,7 +401,7 @@ Factor represents the domain in which a numerical quantity exists.
406401
We are most familiar with the pure-number domain, including all the counting numbers,
407402
the decimal numbers, and the so-called "real" numbers.
408403

409-
Slightly less familiar are numbers like $2\pi$ (we call the domain of such numbers "radians"), $\log_e 2$, $e^2$, and $√2$.
404+
Slightly less familiar are numbers like $2\pi$ (we call the domain of such numbers "radians"), $\log_e 2$, $e2$, and $√2$.
410405
All these numbers can be represented exactly by judicious use of the following classes.
411406

412407
The hierarchy of _Factor_ is as follows:
@@ -429,7 +424,7 @@ The inverse power (which root) is a _Rational_ in the case of _InversePower_ but
429424

430425
These allow certain quantities to be expressed exactly, for example, $sin(\frac{\pi}{3})$ is the square root of $\frac{3}{4}$.
431426
The true (_Scalar_) values of the logarithmic numbers are
432-
$e^x$, $2^x$, and $10^x$ respectively, where $x$ is the "value" of the _Number_.
427+
$ex$, $2x$, and $10x$ respectively, where $x$ is the "value" of the _Number_.
433428

434429
Trigonometrical functions are designed to work with _Radian_ quantities.
435430
Such values are limited (modulated) to be in the range $-\pi...\pi$.
@@ -443,9 +438,9 @@ Similarly, if you use the _atan_ method on a _Scalar_ number, the result will be
443438

444439
The 𝜀 factor works quite differently.
445440
It is not a simple matter of scaling.
446-
A _Number_ of the form _Number(x, NatLog)_ actually evaluates to $e^x$ rather than $e x$.
441+
A _Number_ of the form _Number(x, NatLog)_ actually evaluates to $ex$ rather than $e x$.
447442

448-
It would be possible to implement $\pi$ values similarly to 𝜀 values (as evaluations of $e^{ix}$).
443+
It would be possible to implement $\pi$ values similarly to 𝜀 values (as evaluations of $e{ix}$).
449444
However, this is not currently done (future enhancement?).
450445
See Complex numbers.
451446

@@ -530,16 +525,16 @@ proportional to exactly 7.
530525

531526
It's important to realize that, to get the benefit of this behavior, you must use the _Expression_ mechanism (not a pure _Number_).
532527

533-
it should "give precise result for sqrt(7)^2" in {
528+
it should "give precise result for sqrt(7)2" in {
534529
val x: Expression = Number(7)
535530
val y = x.sqrt
536-
val z = y ^ 2
531+
val z = y 2
537532
z.materialize shouldBe Number(7)
538533
}
539-
it should "show ^2 and sqrt for illustrative purposes" in {
534+
it should "show 2 and sqrt for illustrative purposes" in {
540535
val seven = Number(7)
541536
val x = seven.sqrt
542-
val y = x power 2
537+
val y = x 2
543538
y shouldEqual Number(7)
544539
y shouldBe Number(7)
545540
}
@@ -580,13 +575,12 @@ The _hierarchy_ of Context is as follows:
580575

581576
Transcendental Numbers
582577
======================
583-
Apart from the special cases of $\pi$ and e, there is no way currently to store
584-
transcendental numbers.
585-
For numbers such as natural log of 2, we can express this lazily through an _Expression_.
586-
A transcendental is based on an expression which can be evaluated.
587-
Other transcendentals that are not based on an expression, are specified
588-
simply as constants, for example, $\gamma$, the Euler-Mascheroni constant.
589-
See the _Introduction.sc_ worksheet for examples.
578+
Transcendental numbers are declared as subtypes of _Transcendental_, although $\pi$ and e are, additionally, declared as _Number_, _Real_, and _Expression_.
579+
A transcendental is declared as a (named) _Expression_, where the expression might simply be a constant.
580+
For example, L2 is defined as the natural log of 2 and has a name: "ln(2)".
581+
Another example is $\gamma$, the Euler-Mascheroni constant.
582+
See the _Introduction.sc_ worksheet for examples of usage.
583+
The current list of transcendental numbers includes: $\pi$, e, $\gamma$, _ln(2)_, _lg(e)_, where _lg_ represents log to the base 2.
590584

591585
Error Bounds (Fuzziness)
592586
========================
@@ -640,7 +634,7 @@ is given by slightly different expressions depending on whether the PDFs are ind
640634
See the code (_Fuzz_) for details.
641635

642636
Things get only slightly more complex when applying monadic (single operand) functions or applying a function such
643-
as $z=x^y$:
637+
as $z=xy$:
644638

645639
In general, when we apply a monadic operator $y=f(x)$ (such as constant factor, as above, or power, or one of the trigonometric operators),
646640
the formula for the relative fuzz of the result $\frac{Δy}{y}$ based on the relative fuzz of the input $\frac{Δx}{x}$ is:
@@ -649,7 +643,7 @@ $$\frac{Δy}{y}=\frac{x \frac{dy}{dx}(x)}{f(x)}\frac{Δx}{x}$$
649643

650644
Constants cancel, powers survive as is and so on.
651645

652-
For example, if $y=e^x$ then
646+
For example, if $y=ex$ then
653647

654648
$$\frac{Δy}{y}=x\frac{Δx}{x}$$
655649

@@ -708,8 +702,8 @@ Note that the type hierarchy is very likely to change in version 1.3
708702
* _NumberLike_ (trait)
709703
* _Numerical_ (trait: most numeric quantities)
710704
* _Field_ (trait: something like the mathematical concept of a field)
711-
* _Real_ (case class: a real number based on one _Number_)
712-
* _Multivariate_ (trait which really should be called Algebraic)
705+
* _Real_ (case class: a "real" number based on one _Number_)
706+
* _Multivariate_ (trait: perhaps should be called "Algebraic")
713707
* _Complex_ (trait: a complex number)
714708
* _BaseComplex_ (abstract class)
715709
* _ComplexCartesian_ (case class: Cartesian form of complex number)
@@ -820,6 +814,7 @@ Other types (for reference):
820814

821815
Versions
822816
========
817+
* Version 1.2.10: Another housekeeping release.
823818
* Version 1.2.9: Mostly minor details that missed the previous version.
824819
* Version 1.2.8: Major restructuring: renamed old _Root_ as _NthRoot_ and introduced new _Root_ which effectively replaced _ReducedQuadraticRoot_.
825820
* Version 1.2.7: Introduced dyadic _Log_ functions and, in general, renamed (natural) _log_ method as _ln_, allowing for new dyadic _log_ method.
@@ -881,7 +876,7 @@ To begin, the hierarchy should look like this:
881876
* _Transcendental_ (as now but extends _Expression_)
882877
* _Field_ (as now, but with _Solution_ and _Series_ included)
883878
* _Real_ (as now a single _Number_)
884-
* _BranchedField_ (similar to _Multivariate_ in that there are multiple solutions or branches--these are the solutions to _Algebraic_s)
879+
* _Multivariate_ (similar to _Multivalued_ in that there are multiple solutions or branches--these are the solutions to _Algebraic_s)
885880
* _Complex_ (as now with two _Number_ fields--real and imaginary--conceivably, we might merge _Complex_ and _Solution_ and insist that the imaginary aspect of a _Number_ is represented in the _Number_ itself)
886881
* _Solution_ (with real roots)
887882
* _Series_

build.sbt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ organization := "com.phasmidsoftware"
22

33
name := "Number"
44

5-
version := "1.2.9"
5+
version := "1.2.10"
66

77
scalaVersion := "2.13.16"
88

99
scalacOptions ++= Seq("-encoding", "UTF-8", "-unchecked", "-deprecation", "-Ywarn-dead-code", "-Ywarn-value-discard", "-Ywarn-unused" )
1010

11+
//Test / unmanagedSourceDirectories += baseDirectory.value / "it/scala"
12+
1113
val scalaTestVersion = "3.2.19"
1214

1315
libraryDependencies ++= Seq(

src/main/scala/com/phasmidsoftware/number/applications/Fibonacci.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ object Fibonacci {
1515
/**
1616
* Represents the golden ratio, denoted as φ (phi), as an instance of `Expression`.
1717
* The golden ratio is a mathematical constant that satisfies the quadratic equation
18-
* `x^2 = x + 1` and is associated with numerous applications in mathematics,
18+
* `x2 = x + 1` and is associated with numerous applications in mathematics,
1919
* art, and nature.
2020
*
2121
* This value can be used in computations involving algebraic expressions,
@@ -42,7 +42,7 @@ object Fibonacci {
4242
*/
4343
def fib(n: Int): BigInt = {
4444
val expression = fibExpression(n)
45-
val errorMessage = s"fib($n) = ${((phi ^ n) - (psi ^ n)) / Constants.root5}"
45+
val errorMessage = s"fib($n) = ${((phi n) - (psi n)) / Constants.root5}"
4646
// CONSIDER should this be PureNumber or Scalar?
4747
expression.materialize match {
4848
case Real(x) => x match {
@@ -61,6 +61,6 @@ object Fibonacci {
6161
}
6262

6363
private[applications] def fibExpression(n: Int): Expression =
64-
((phi ^ n) - (psi ^ n)) / Constants.root5
64+
((phi n) - (psi n)) / Constants.root5
6565
}
6666

src/main/scala/com/phasmidsoftware/number/core/BaseComplex.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ abstract class BaseComplex(val real: Number, val imag: Number) extends Complex {
183183
case (ComplexCartesian(_, Number.zeroR), x) =>
184184
power(x)
185185
case _ =>
186-
throw NumberException(s"power not supported for: $this ^ $p")
186+
throw NumberException(s"power not supported for: $this $p")
187187
}
188188

189189
/**
@@ -552,7 +552,7 @@ case class ComplexCartesian(x: Number, y: Number) extends BaseComplex(x, y) {
552552
/**
553553
* Computes the square of a complex number represented in Cartesian form.
554554
* The result is a new `ComplexCartesian` value obtained by applying the formula:
555-
* (x^2 - y^2, 2xy), where `x` and `y` are the real and imaginary parts respectively.
555+
* (x2 - y2, 2xy), where `x` and `y` are the real and imaginary parts respectively.
556556
*
557557
* @return a `ComplexCartesian` instance representing the square of the original complex number.
558558
*/
@@ -849,21 +849,21 @@ case class ComplexPolar(r: Number, theta: Number, n: Int = 1) extends BaseComple
849849
case Value(0) | Value(_, Rational.zero) | Value(_, _, 0.0) =>
850850
"\u00b1" + rAsString // +-
851851
case _ =>
852-
s"${rAsString}e^${showImaginary(polar = true)}"
852+
s"${rAsString}e${showImaginary(polar = true)}"
853853
}
854854
case (_, _, 3) =>
855855
val rAsString = r.render
856856
theta.nominalValue match {
857857
case Value(0) | Value(_, Rational.zero) | Value(_, _, 0.0) =>
858-
s"{$rAsString, ±${rAsString}e^${showImaginary(polar = true, 1, 3)}}"
858+
s"{$rAsString, ±${rAsString}e${showImaginary(polar = true, 1, 3)}}"
859859
case _ =>
860-
s"${rAsString}e^${showImaginary(polar = true)}"
860+
s"${rAsString}e${showImaginary(polar = true)}"
861861
}
862862
// TODO handle the case where n is greater than 2
863863
case _ =>
864864
val rAsString = r.render
865865
val w = showImaginary(polar = true)
866-
if (w == "0") rAsString else s"${rAsString}e^$w"
866+
if (w == "0") rAsString else s"${rAsString}e$w"
867867
}
868868

869869
/**

src/main/scala/com/phasmidsoftware/number/core/Constants.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,12 @@ object Constants {
191191
/**
192192
* [[https://en.wikipedia.org/wiki/Planck_constant]] (exact).
193193
*/
194-
lazy val planck: Real = Real("6.6260701500E-34") // J Hz ^ -1
194+
lazy val planck: Real = Real("6.6260701500E-34") // J Hz -1
195195

196196
/**
197197
* [[https://en.wikipedia.org/wiki/Speed_of_light]] (exact).
198198
*/
199-
lazy val c: Real = Real("299792458") // m sec ^ -1
199+
lazy val c: Real = Real("299792458") // m sec -1
200200

201201
/**
202202
* [[https://en.wikipedia.org/wiki/Proton-to-electron_mass_ratio]]
@@ -227,6 +227,6 @@ object Constants {
227227
*/
228228
val sPhi = "1.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475"
229229
val sGamma = "0.57721566490153286060651209008240243104215933593992*"
230-
val sG = "6.67430(15)E-11" // m ^ 3 kg ^ -1 s ^ -2
231-
val sBoltzmann = "1380649.E-29" // J K ^ -1
230+
val sG = "6.67430(15)E-11" // m 3 kg -1 s -2
231+
val sBoltzmann = "1380649.E-29" // J K -1
232232
}

src/main/scala/com/phasmidsoftware/number/core/ExactNumber.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import java.util.Objects
1111
* This class is designed to model an exact Numeral.
1212
* See GeneralNumber for more details on the actual representation.
1313
*
14-
* TODO implement scientific notation by having factors such os 10^3, 10^6, etc. (alternatively, add a separate parameter)
14+
* TODO implement scientific notation by having factors such os 103, 106, etc. (alternatively, add a separate parameter)
1515
*
1616
* @param nominalValue the nominalValue of the Number, expressed as a nested Either type.
1717
* @param factor the scale factor of the Number: valid scales are: PureNumber, Radian, and NatLog.
@@ -80,9 +80,13 @@ case class ExactNumber(override val nominalValue: Value, override val factor: Fa
8080
def simplify: Number = (factor, nominalValue) match {
8181
case (Logarithmic(_), Right(0)) =>
8282
Number.one
83-
case (Euler, Right(1)) => // this is `e^i𝛑`, which equals `-1` by Euler's Identity
83+
case (Logarithmic(_), Left(Right(Rational.negInfinity))) =>
84+
Number.zero
85+
case (Logarithmic(_), Left(Right(Rational.infinity))) =>
86+
ExactNumber(Value.fromRational(Rational.infinity), PureNumber)
87+
case (Euler, Right(1)) => // this is `e∧i𝛑`, which equals `-1` by Euler's Identity
8488
Number(-1)
85-
case (Euler, Left(Right(Rational.half))) => // this is `e^i𝛑/2`, which equals `i` by Euler's Identity
89+
case (Euler, Left(Right(Rational.half))) => // this is `ei𝛑/2`, which equals `i` by Euler's Identity
8690
Number.i
8791
// XXX this handles all roots (of which there are currently only SquareRoot and CubeRoot)
8892
case (NthRoot(n), v) =>
@@ -256,7 +260,7 @@ case class ExactNumber(override val nominalValue: Value, override val factor: Fa
256260
val sb = new StringBuilder()
257261
factor match {
258262
case Euler =>
259-
sb.append(s"e^i${Value.valueToString(nominalValue, skipOne = true)}𝛑")
263+
sb.append(s"ei${Value.valueToString(nominalValue, skipOne = true)}𝛑")
260264
case Logarithmic(_) =>
261265
sb.append(factor.render(nominalValue))
262266
case Scalar(_) =>

src/main/scala/com/phasmidsoftware/number/core/Number.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,15 +880,15 @@ object Number {
880880
* @param y the exponent, an Int.
881881
* @return a Number whose value is x / y.
882882
*/
883-
def ^(y: Int): Number = x ^ y // TESTME
883+
def (y: Int): Number = x y // TESTME
884884

885885
/**
886886
* Raise x to the power of y (an Rational) and yield a Number.
887887
*
888888
* @param y the exponent, a Rational.
889889
* @return a Number whose value is x / y.
890890
*/
891-
def ^(y: Rational): Number = x ^ y // TESTME
891+
def (y: Rational): Number = x y // TESTME
892892
}
893893

894894
/**

0 commit comments

Comments
 (0)