Common Lisp: Numbers
lispcookbook.github.io
lispcookbook.github.io
This all directly falls out of a mathematical formalism called “computable real numbers” [1] which are the (countable!) set of real numbers for which an algorithm exists to compute the digits to any desired precision. (Usually binary digits are the standard way to write out the definition of a computable number.)
Note that I first meet computable numbers in Haskell : https://wiki.haskell.org/Applications_and_libraries/Mathemat...
I’ve used this package to get exact real computations in Haskell which get evaluated at n bits when needed for printing or equality checking etc.
Sometimes it’s unavoidable though, such as when checking equality where you have to call it quits at some point at some precision.
This is quite inefficient for things like summing over a list. Or really, any kind of accumulation.
Edit: looking into it was just reading futher on wikipedia. Even ordering is undecidable.
In general this works well.
[EDITED to add:] I checked; the implementation here indeed won't recognize that you're dividing something by itself. For the avoidance of doubt, nor do I think trying to recognize such things would be an improvement.
(Also, if you ask for e.g. the digit immediately preceding the decimal point, you will wait for ever because no amount of precision will enable the implementation to tell whether your number is just less than 1 or 1 or just over. So don't ask it for that, ask it for a very close approximation and draw your own conclusions.)
Even if you have computer algebra, math says it's not possible to check that arbitrary expressions are equal. It's an undecidable problem. So with that, I don't fault a computable reals package not being able to detect that x == y in an expression x/y.
(And I wonder idly from time to time about making one that does know a bit about some particularly nice classes of number -- e.g., algebraic numbers -- and does all the things you'd like it to as long as you stay within such a class. Obviously as soon as you ask it for sqrt(2)+pi all that would go out the window.)
If 0/0 = Q, then
0 = 0 × Q. So, we get to define this operation. If we treat 0 as an integer, then we could treat Q (a set) like a 1 x inf. matrix and we have scalar multiplication.
But
0 × Q = [0]' × Q
So 0 can be an infinite set of 0. This is cyclical, I know. This cyclical nature leads to an interesting effect if we also define integer division. Try this around 0 in Q.
We could also define the × as an inner (dot) product, or as a cross product.
This is fun!
And I guess it is easy to define one more dimension of number.
Python and Ruby are probably the only popular ones that ship by default with unlimited precision integers.
For arbitrary precision reals in Python, there is mpmath http://mpmath.org/ . There is also the standard decimal module which "provides support for fast correctly-rounded decimal floating point arithmetic" : https://docs.python.org/3/library/decimal.html
Perl: https://perldoc.perl.org/bignum.html
Perl6: https://docs.perl6.org/language/math#Arithmetic
https://docs.julialang.org/en/v1/manual/integers-and-floatin...
If I remember correctly, Elixir uses arbitrary precision integers by default, though I'm not sure about float.
https://stackoverflow.com/questions/8676331/how-to-run-a-has...
GCC hash-bang is still an edit-compile-link-debug cycle. Just like with Python and Ruby, Haskell hash-bang accelerates the cycle by jettisoning the compile and linking steps.
The benefit of scripts is that each file is a self-contained single source of truth.
Python implements a caching scheme for .pyc files; maybe it's not a scripting language ...
If I were to venture an opinion on why C (in its usual implementations) is not a scripting language it would be:
- no interactive prompt (REPL).
- no reloading of code (other than clumsy, fragile, platform-specific shared lib mechanisms).
- no execution of "top level forms": a program's entry point is a specific function (main on hosted implementations). When, e.g., Lisp code is compiled, the effect of loading the compiled file is still the same as of the source file: the top-level forms (now in a compiled form) are executed one by one. (What's a "script"? A file with instructions to be run one by one.)
- no late binding; in fact, no program at all, unless all external references are satisfied. Scripting languages can run code that contains references to unknown global variables, or calls to unknown functions. These can be loaded late.
Fun fact: the SBCL implementation of Common Lisp actually adds a shebang to its compiled, binary Lisp files, so you can compile your Lisp script and then execute it from the shell.
$ cat > foo.tl
#!/usr/bin/txr
(pprinl "hello")
$ txr -e '(compile-file "foo")'
hello
$ cat foo.tlo
#!/usr/bin/txr
(5 0 nil)
((2 3 #b'0200012400000004 02000010' #("hello") #(usr:pprinl)))
If the source file doesn't have a hash bang line, the one isn't output.You'd think SBCL wouldn't need this sort of thing since it compiles to native code?
Also, the buit-in Decimal class is horribly slow by comparison to gmpy2.
racket has exact numbers of unlimited size.
1. Most Lisp dialects, including Scheme and ANSI Lisp, have interactive modes for evaluating expressions.
2. Most Lisp dialects have a mode of processing files in the same manner: reading individual forms and evaluating them immediately. I.e. it is not necessary to translate files into objects that have to be linked to produce an executable program.
Incredibly fast with support for quaternions / spherical coordinate systems etc
One can easily generate random integer-valued lisp forms without having to do much checking that integers are in range. In C or other languages with bounded integer size it's much tougher (see Regehr et al.'s Csmith). It's also tough to reduce a failing test case without introducing bad behavior in C; in Lisp it's straightfoward.