<commit_before>#
#
#            Nim's Runtime Library
#        (c) Copyright 2015 <NAME>
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## *Constructive mathematics is naturally typed.* -- <NAME>
##
## Basic math routines for Nim.
##
## Note that the trigonometric functions naturally operate on radians.
## The helper functions `degToRad<#degToRad,T>`_ and `radToDeg<#radToDeg,T>`_
## provide conversion between radians and degrees.
##
## .. code-block::
##
##   import math
##   from sequtils import map
##
##   let a = [0.0, PI/6, PI/4, PI/3, PI/2]
##
##   echo a.map(sin)
##   # @[0.0, 0.499…, 0.707…, 0.866…, 1.0]
##
##   echo a.map(tan)
##   # @[0.0, 0.577…, 0.999…, 1.732…, 1.633…e+16]
##
##   echo cos(degToRad(180.0))
##   # -1.0
##
##   echo sqrt(-1.0)
##   # nan   (use `complex` module)
##
## This module is available for the `JavaScript target
## <backends.html#backends-the-javascript-target>`_.
##
## **See also:**
## * `complex module<complex.html>`_ for complex numbers and their
##   mathematical operations
## * `rationals module<rationals.html>`_ for rational numbers and their
##   mathematical operations
## * `fenv module<fenv.html>`_ for handling of floating-point rounding
##   and exceptions (overflow, zero-divide, etc.)
## * `random module<random.html>`_ for fast and tiny random number generator
## * `mersenne module<mersenne.html>`_ for Mersenne twister random number generator
## * `stats module<stats.html>`_ for statistical analysis
## * `strformat module<strformat.html>`_ for formatting floats for print
## * `system module<system.html>`_ Some very basic and trivial math operators
##   are on system directly, to name a few ``shr``, ``shl``, ``xor``, ``clamp``, etc.


import std/private/since
{.push debugger: off.} # the user does not want to trace a part
                       # of the standard library!

import bitops, fenv

when defined(c) or defined(cpp):
  proc c_isnan(x: float): bool {.importc: "isnan", header: "<math.h>".}
    # a generic like `x: SomeFloat` might work too if this is implemented via a C macro.

func binom*(n, k: int): int =
  ## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
  runnableExamples:
    doAssert binom(6, 2) == binom(6, 4)
    doAssert binom(6, 2) == 15
    doAssert binom(-6, 2) == 1
    doAssert binom(6, 0) == 1
  if k <= 0: return 1
  if 2*k > n: return binom(n, n-k)
  result = n
  for i in countup(2, k):
    result = (result * (n + 1 - i)) div i

func createFactTable[N: static[int]]: array[N, int] =
  result[0] = 1
  for i in 1 ..< N:
    result[i] = result[i - 1] * i

func fac*(n: int): int =
  ## Computes the `factorial <https://en.wikipedia.org/wiki/Factorial>`_ of
  ## a non-negative integer ``n``.
  ##
  ## See also:
  ## * `prod func <#prod,openArray[T]>`_
  runnableExamples:
    doAssert fac(3) == 6
    doAssert fac(4) == 24
    doAssert fac(10) == 3628800
  const factTable =
    when sizeof(int) == 2:
      createFactTable[5]()
    elif sizeof(int) == 4:
      createFactTable[13]()
    else:
      createFactTable[21]()
  assert(n >= 0, $n & " must not be negative.")
  assert(n < factTable.len, $n & " is too large to look up in the table")
  factTable[n]

{.push checks: off, line_dir: off, stack_trace: off.}

when defined(Posix) and not defined(genode):
  {.passl: "-lm".}

const
  PI* = 3.1415926535897932384626433          ## The circle constant PI (Ludolph's number)
  TAU* = 2.0 * PI                            ## The circle constant TAU (= 2 * PI)
  E* = 2.71828182845904523536028747          ## Euler's number

  MaxFloat64Precision* = 16                  ## Maximum number of meaningful digits
                                             ## after the decimal point for Nim's
                                             ## ``float64`` type.
  MaxFloat32Precision* = 8                   ## Maximum number of meaningful digits
                                             ## after the decimal point for Nim's
                                             ## ``float32`` type.
  MaxFloatPrecision* = MaxFloat64Precision   ## Maximum number of
                                             ## meaningful digits
                                             ## after the decimal point
                                             ## for Nim's ``float`` type.
  MinFloatNormal* = 2.225073858507201e-308   ## Smallest normal number for Nim's
                                             ## ``float`` type. (= 2^-1022).
  RadPerDeg = PI / 180.0                     ## Number of radians per degree

type
  FloatClass* = enum ## Describes the class a floating point value belongs to.
                     ## This is the type that is returned by
                     ## `classify func <#classify,float>`_.
    fcNormal,        ## value is an ordinary nonzero floating point value
    fcSubnormal,     ## value is a subnormal (a very small) floating point value
    fcZero,          ## value is zero
    fcNegZero,       ## value is the negative zero
    fcNan,           ## value is Not-A-Number (NAN)
    fcInf,           ## value is positive infinity
    fcNegInf         ## value is negative infinity

func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} =
  ## Returns whether `x` is a `NaN`, more efficiently than via `classify(x) == fcNan`.
  ## Works even with: `--passc:-ffast-math`.
  runnableExamples:
    doAssert NaN.isNaN
    doAssert not Inf.isNaN
    doAssert isNaN(Inf - Inf)
    doAssert not isNan(3.1415926)
    doAssert not isNan(0'f32)

  template fn: untyped = result = x != x
  when nimvm: fn()
  else:
    when defined(js): fn()
    else: result = c_isnan(x)

func classify*(x: float): FloatClass =
  ## Classifies a floating point value.
  ##
  ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
  ## Doesn't work with: `--passc:-ffast-math`.
  runnableExamples:
    doAssert classify(0.3) == fcNormal
    doAssert classify(0.0) == fcZero
    doAssert classify(0.3/0.0) == fcInf
    doAssert classify(-0.3/0.0) == fcNegInf
    doAssert classify(5.0e-324) == fcSubnormal
<commit_msg>docs minor for math (#16407)<commit_after>#
#
#            Nim's Runtime Library
#        (c) Copyright 2015 <NAME>
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## *Constructive mathematics is naturally typed.* -- <NAME>
##
## Basic math routines for Nim.
##
## Note that the trigonometric functions naturally operate on radians.
## The helper functions `degToRad<#degToRad,T>`_ and `radToDeg<#radToDeg,T>`_
## provide conversion between radians and degrees.
##
## .. code-block::
##
##   import math
##   from sequtils import map
##
##   let a = [0.0, PI/6, PI/4, PI/3, PI/2]
##
##   echo a.map(sin)
##   # @[0.0, 0.499…, 0.707…, 0.866…, 1.0]
##
##   echo a.map(tan)
##   # @[0.0, 0.577…, 0.999…, 1.732…, 1.633…e+16]
##
##   echo cos(degToRad(180.0))
##   # -1.0
##
##   echo sqrt(-1.0)
##   # nan   (use `complex` module)
##
## This module is available for the `JavaScript target
## <backends.html#backends-the-javascript-target>`_.
##
## **See also:**
## * `complex module<complex.html>`_ for complex numbers and their
##   mathematical operations
## * `rationals module<rationals.html>`_ for rational numbers and their
##   mathematical operations
## * `fenv module<fenv.html>`_ for handling of floating-point rounding
##   and exceptions (overflow, zero-divide, etc.)
## * `random module<random.html>`_ for fast and tiny random number generator
## * `mersenne module<mersenne.html>`_ for Mersenne twister random number generator
## * `stats module<stats.html>`_ for statistical analysis
## * `strformat module<strformat.html>`_ for formatting floats for print
## * `system module<system.html>`_ Some very basic and trivial math operators
##   are on system directly, to name a few ``shr``, ``shl``, ``xor``, ``clamp``, etc.


import std/private/since
{.push debugger: off.} # the user does not want to trace a part
                       # of the standard library!

import bitops, fenv

when defined(c) or defined(cpp):
  proc c_isnan(x: float): bool {.importc: "isnan", header: "<math.h>".}
    # a generic like `x: SomeFloat` might work too if this is implemented via a C macro.

func binom*(n, k: int): int =
  ## Computes the `binomial coefficient <https://en.wikipedia.org/wiki/Binomial_coefficient>`_.
  runnableExamples:
    doAssert binom(6, 2) == binom(6, 4)
    doAssert binom(6, 2) == 15
    doAssert binom(-6, 2) == 1
    doAssert binom(6, 0) == 1
  if k <= 0: return 1
  if 2*k > n: return binom(n, n-k)
  result = n
  for i in countup(2, k):
    result = (result * (n + 1 - i)) div i

func createFactTable[N: static[int]]: array[N, int] =
  result[0] = 1
  for i in 1 ..< N:
    result[i] = result[i - 1] * i

func fac*(n: int): int =
  ## Computes the `factorial <https://en.wikipedia.org/wiki/Factorial>`_ of
  ## a non-negative integer ``n``.
  ##
  ## See also:
  ## * `prod func <#prod,openArray[T]>`_
  runnableExamples:
    doAssert fac(3) == 6
    doAssert fac(4) == 24
    doAssert fac(10) == 3628800
  const factTable =
    when sizeof(int) == 2:
      createFactTable[5]()
    elif sizeof(int) == 4:
      createFactTable[13]()
    else:
      createFactTable[21]()
  assert(n >= 0, $n & " must not be negative.")
  assert(n < factTable.len, $n & " is too large to look up in the table")
  factTable[n]

{.push checks: off, line_dir: off, stack_trace: off.}

when defined(Posix) and not defined(genode):
  {.passl: "-lm".}

const
  PI* = 3.1415926535897932384626433          ## The circle constant PI (Ludolph's number)
  TAU* = 2.0 * PI                            ## The circle constant TAU (= 2 * PI)
  E* = 2.71828182845904523536028747          ## Euler's number

  MaxFloat64Precision* = 16                  ## Maximum number of meaningful digits
                                             ## after the decimal point for Nim's
                                             ## ``float64`` type.
  MaxFloat32Precision* = 8                   ## Maximum number of meaningful digits
                                             ## after the decimal point for Nim's
                                             ## ``float32`` type.
  MaxFloatPrecision* = MaxFloat64Precision   ## Maximum number of
                                             ## meaningful digits
                                             ## after the decimal point
                                             ## for Nim's ``float`` type.
  MinFloatNormal* = 2.225073858507201e-308   ## Smallest normal number for Nim's
                                             ## ``float`` type. (= 2^-1022).
  RadPerDeg = PI / 180.0                     ## Number of radians per degree

type
  FloatClass* = enum ## Describes the class a floating point value belongs to.
                     ## This is the type that is returned by
                     ## `classify func <#classify,float>`_.
    fcNormal,        ## value is an ordinary nonzero floating point value
    fcSubnormal,     ## value is a subnormal (a very small) floating point value
    fcZero,          ## value is zero
    fcNegZero,       ## value is the negative zero
    fcNan,           ## value is Not-A-Number (NAN)
    fcInf,           ## value is positive infinity
    fcNegInf         ## value is negative infinity

func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} =
  ## Returns whether `x` is a `NaN`, more efficiently than via `classify(x) == fcNan`.
  ## Works even with: `--passc:-ffast-math`.
  runnableExamples:
    doAssert NaN.isNaN
    doAssert not Inf.isNaN
    doAssert isNaN(Inf - Inf)
    doAssert not isNaN(3.1415926)
    doAssert not isNaN(0'f32)

  template fn: untyped = result = x != x
  when nimvm: fn()
  else:
    when defined(js): fn()
    else: result = c_isnan(x)

func classify*(x: float): FloatClass =
  ## Classifies a floating point value.
  ##
  ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_.
  ## Doesn't work with: `--passc:-ffast-math`.
  runnableExamples:
    doAssert classify(0.3) == fcNormal
    doAssert classify(0.0) == fcZero
    doAssert classify(0.3/0.0) == fcInf
    doAssert classify(-0.3/0.0) == fcNegInf
    doAssert classify(5.0e-324) == fcSubnormal

{'fraction_non_alphanumeric': 0.13435747378688126, 'fraction_numerical': 0.03730797366495977, 'mean_word_length': 2.4187274242845236, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 45, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3552950', 'n_tokens_mistral': 4272, 'n_tokens_neox': 3826, 'n_words': 1240}