6

I'd like to take more digits of the Prelude pi value.

Prelude> take 4 $ show pi
"3.14"

But

Prelude> take 17 $ show pi
"3.141592653589793"

Prelude> take 170 $ show pi
"3.141592653589793"

Is the pi constant just stored this truncated? Is there an option in show to print to string more digits?

Mittenchops
  • 18,633
  • 33
  • 128
  • 246

2 Answers2

14

pi is a method of the Floating class:

class Fractional a => Floating a where
  pi :: a
  ...

So pi is polymorphic, and it is up to the implementor of the instance to define it appropriately.

The most common instances are Float and Double which have limited precision:

Prelude> pi :: Float
3.1415927
Prelude> pi :: Double
3.141592653589793

but nothing is stopping you from using other packages, like long-double which gives a few more bits on some systems:

Numeric.LongDouble> pi :: LongDouble 
3.1415926535897932385

Or rounded which gives arbitrarily many bits of precision via the MPFR software implementation:

Numeric.Rounded> pi :: Rounded TowardNearest 100
3.1415926535897932384626433832793
Numeric.Rounded> pi :: Rounded TowardNearest 500
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081283

The numbers package provides a pure-Haskell implementation of constructive (exact) real numbers, which can be shown to as many digits as desired:

Data.Number.CReal> showCReal 100 pi
"3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"

You can also have lower precision with the half package, maybe interoperable with GPU:

Numeric.Half> pi :: Half
3.140625

When you evaluate pi without giving a specific type, the interpreter's defaulting rules come into play.

Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. ... If no default declaration is given in a module then it assumed to be: default (Integer, Double) -- https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4

Prelude> :t pi
pi :: Floating a => a

Integer is not Floating, but Double is, so the ambiguous type gets resolved by defaulting to Double. You can get more information by enabling -Wtype-defaults:

Prelude> :set -Wtype-defaults 
Prelude> pi

<interactive>:2:1: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Double’
        (Show a0) arising from a use of ‘print’ at <interactive>:2:1-2
        (Floating a0) arising from a use of ‘it’ at <interactive>:2:1-2
    • In a stmt of an interactive GHCi command: print it
3.141592653589793

(Note: I wrote the long-double package and am the current maintainer of rounded.)

Claude
  • 1,014
  • 7
  • 13
  • Would also be good to point out that `show pi` typechecks due to defaulting rules – jberryman Dec 27 '18 at 15:55
  • NB: the `numbers` package was unmaintained for a few years, and the new maintainer isn't all that active (there are still open pull requests from 2014) – Jeremy List Jan 18 '19 at 00:18
  • Sorry but I am having a little bit of difficulty accessing that `Data.Number.CReal`? I am using **Haskell GHC 8.10.3**. How do you import it since I am getting *"Could not find module `Data.Number.CReal`"*? I figured you can install `numbers` (https://hackage.haskell.org/package/numbers-3000.2.0.2) package using `cabal install --lib numbers`, but still I cannot import. – Tom Charles Zhang Jan 19 '21 at 00:59
0

Pi defined as

 pi = 3.141592653589793238

So there is all digits you can have. Keep in mind that Floating typeclass is used to represent it.

talex
  • 17,973
  • 3
  • 29
  • 66
  • 1
    Well, `pi` isn't really defined this way, it's only [the standard implementation in the `Double` instance](http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Float.html#line-521). Interestingly [also in `Float`](http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Float.html#line-376), although that can't even represent that many digits. But, as Claude says `pi` can have different implementations, including ones that can yield arbitrarily many digits. – leftaroundabout Dec 27 '18 at 10:35
  • Yes. You can have different `pi` for different type, but in this case we use this definition. – talex Dec 27 '18 at 10:37