Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scientific Notation Conversion - Scheme

I am trying to do simple subtraction arithmetic on two very large numbers.

(- 1.8305286640724363e+023 (floor 1.8305286640724363e+023))

When I do this, I get a result of 0.0. I'm expecting an output of:

(- 1.8305286640724363e+023 (floor 1.8305286640724363e+023)) => .2439521

The expanded scientific notation would give me that answer.

183052866407243622723319.24395251 - 183052866407243622723319.00 = .2439521

I would like to represent these numbers as they are, with the decimal numbers in place, as opposed to scientific notation, so I can achieve the desired result. Is there a way of doing this within Scheme? Any help, guidance, or reference would be much appreciated :)

I am using DrRacket for Windows 64bit and R5RS Language.

EDIT

I figured I'd be as specific as possible regarding an example of thearithmetic I'm performing.

arithmetic:

(* 271979577247970257395 0.6180339887) => 1.6809262297150285e+020

When doing this same multiplication in a calculator, the result yeilds => 168092622971502827156.7975214365

When trying to use exact or inexact I get this:

(exact (* 271979577247970257395 0.6180339887)) => exact: undefined;
(inexact (* 271979577247970257395 0.6180339887)) => inexact: undefined;

I suppose R5RS doesn't support exact/inexact? I looked it up and examples show to use inexact->exact procedure so I did and got this:

(inexact->exact (* 271979577247970257395 0.6180339887)) => 168092622971502854144

And just for specificity, I did the opposite:

(exact->inexact (* 271979577247970257395 0.6180339887)) => 1.6809262297150285e+020

So then I tried using Big Float as someone mentioned:

(bf-precision 128)
(bf (* 271979577247970257395 0.6180339887)) => (bf 168092622971502854144)

Giving me the same output as exact. All I simply want is to save get the number I would get from a calculator and it seems like a very difficult task! I'm sorry I might sound stupid for not getting this, just keep in mind I'm an extreme amateur in SCHEME. Thanks again for your help! :)

like image 838
Sixers17 Avatar asked Apr 15 '13 06:04

Sixers17


2 Answers

The problem is that you have more significant digits in the input than Racket uses in its internal representation.

Let us enter the bare numbers:

> 183052866407243622723319.24395251
1.8305286640724363e+23

> 183052866407243622723319.00
1.8305286640724363e+23

Both numbers are thus represented as the same (whole) number internally. This explains why your result was 0.

This behaviour is not limited to Racket. In fact Racket follows the IEEE standard for computing with 64-bit floating-point numbers. You will get same result in other programming languages.

If you need to compute why greater precision you can use bigfloats instead.

(require math/bigfloat)
(bf-precision 128) ; use 128 bits
(bf- (bf #e183052866407243622723319.24395251)
     (bfround (bf #e183052866407243622723319.00)))

The result is: (bf #e0.2439525099999997337363311089575290679932)

Note: To use bigfloats make sure you have a recent version of Racket.

Update: In case you wonder why the result wasn't .2439521 the answer is that the result and .2439521 is represented by the same internal bitpattern.

Update:

If you want to turn the result back into a standard floating point, use bigfloat->flonum.

(bf-precision 256)  ; to get more decimal digits correct
(bigfloat->flonum
   (bf- (bf #e183052866407243622723319.24395251)
        (bfround (bf #e183052866407243622723319.00))))

This gives the result: 0.24395251

Addendum:

Racket (and Scheme) reads numbers with decimal points as floating point numbers. If you prefix a number with #e it is read as an exact number (that is the resulting value is an exact fraction). You can use this to keep the exact decimals. You exact numbers for your entire computation, and then in the end use exact->inexact to turn the result into a floating point number. Here is your example:

> (exact->inexact 
     (- #e183052866407243622723319.24395251
        #e183052866407243622723319.00))
0.24395251
like image 67
soegaard Avatar answered Oct 14 '22 02:10

soegaard


Of course, with Scheme you've got exact numbers:

(define x (+ (exact 183052866407243622723319) (exact .24395251)))
(define y (+ (exact 183052866407243622723319) (exact .0)))

I split x to avoid having the Scheme reader truncate the value. Then:

> x
3297587283763054256749149618043779713285/18014398509481984
> (- x y)
4394657732528389/18014398509481984
> (inexact (- x y))
0.24395251

[edit] You need to use exact numbers throughout the computation. That means convert your input to exact and then at the end convert your output in inexact (if desired).

As for your attempt at #e(* 27... 0.6...) - that won't work because the #e applies to numbers, not expressions. use (* #e27... #e0.6...).

> (* #e271979577247970257395 #e0.6180339887)
336185245943005654313595042873/2000000000
like image 4
GoZoner Avatar answered Oct 14 '22 00:10

GoZoner