Giter Club home page Giter Club logo

elixir-number's Introduction

Numbers

hex.pm version Build Status Inline docs

Numbers is a tiny Elixir package that facilitates the creation of libraries that want to be able to use any kind of Numberlike type.

Some known custom numeric types that implement Numbers' protocols:

  • Ratio -- rational numbers.
  • Decimal -- arbitrary precision decimal numbers.
  • Tensor -- Vectors, Matrices and higher-order tensors.
  • ComplexNum -- Complex numbers.

Just add one (or multiple) of these libraries to your project, together with Numbers, and you're good to go!

How does it work?

Starting at version 5, Numbers contains a set of protocols that can be independently implemented for your data structures.

Each protocol maps to a single arithmetical operation that your data structure might support.

Because protocols are used, Numbers can dispatch quite fast! Also, Numbers does not restrict your modules to any special naming schemes (as was the case with older versions of Numbers that used a Behaviour).

The following operations are supported:

  • add for addition, by implementing Numbers.Protocols.Addition.
  • sub for subtraction, by implementing Numbers.Protocols.Subtraction.
  • mult for multiplication, by implementing Numbers.Protocols.Multiplication.
  • div for division, by implementing Numbers.Protocols.Division.
  • minus for unary minus (negation), by implementing Numbers.Protocols.Minus.
  • abs to calculate the absolute value of a number, by implementing Numbers.Protocols.Absolute.
  • pow for calculating integer powers, by implementing Numbers.Protocols.Exponentiation. A special helper in Numbers.Helpers.pow_by_sq can be used inside this implementation to automatically make use of the 'Exponentiation by Squaring' algorithm.
  • to_float for (possibly lossy) conversion to the built-in Float datatype, by implementing Numbers.Protocols.ToFloat.

Coercion

Numbers does not automatically transform numbers from one type to another if one of the functions is called with two different types.

Frequently you do want to use other data types together with your custom data type. For this, a custom coercion can be specified, using Coerce.defcoercion as exposed by the Coerce library that Numbers depends on.

The only coercion that ships with Numbers itself, is a coercion of Integers to Floats, meaning that they work the same way as when using the standard library math functions with these types.

Overloaded Operators

You can opt-in to overloaded +, -, *, / operators by calling use Numbers, overload_operators: true. This allows you to use these inline operators for all other Numberlike types.

The library uses a conditional compilation technique to make sure that you will still be able to use the operators inside guards for built-in integers and floats.

As example consider:

defmodule An.Example do
  use Numbers, overload_operators: true

  def foo(a, b) when a + b < 10 do  # Uses the normal guard-safe '+' operator (e.g. Kernel.+/2)
    42
  end
  def foo(c, d) do 
    c + d # Uses the overloaded '+' operator.
  end
end

Examples:

Using built-in numbers:

iex> alias Numbers, as: N

iex> N.add(1, 2)
3

iex> N.mult(3,5)
15

iex> N.mult(1.5, 100)
150.0

Using Decimals: (requires the Decimal library.)

iex> alias Numbers, as: N

iex> d = Decimal.new(2)
iex> N.div(d, 10)
#Decimal<0.2>
iex> small_number = N.div(d, 1234)
#Decimal<0.001620745542949756888168557536>
iex> N.pow(small_number, 100)

Installation

The package can be installed as:

  1. Add numbers to your list of dependencies in mix.exs:
def deps do
  [{:numbers, "~> 5.2"}]
end

Changelog

  • 5.2.4 Updates :decimal dependency to now allow both version 1.x as well as version 2.x.
  • 5.2.3 Updates :decimal dependency to 1.9 or newer, and replaces deprecated Decimal.minus/1 call with Decimal.negate/1
  • 5.2.2 Updated mix.exs to use extra_applications rather than manually overridding applications. This drops support for now very old versions of Elixir (< v1.4) but ensures proper support with Elixir v1.11 and beyond.
  • 5.2.1 Better error message when wrongly using an operator at the left side of a match (e.g. a - 1 = 10).
  • 5.2.0 Ensures that overloaded operators do not prevent built-in operators to be used in guards.
  • 5.1.1 Makes Decimal dependency version less specific to play nicer with other libraries :-).
  • 5.1.0 Possibility to import overloaded operator variants. Also, greatly improved documentation.
  • 5.0.0 MAJOR OVERHAUL: New implementation based on a set of Protocols. Should be a lot faster and easier on implementers. Also uses a new method to perform coercions based on the Coerce library. Announcement post
  • 4.0.0 Breaking change: Move Numeric to Numbers.Numeric, to follow proper code organization conventions.
  • 3.0.1 Improved README
  • 3.0.0 Remove public Numbers.coerce/2 function, as it had confused naming and very limited use. Added optional Numeric.coerce/2 callback (which works very different from the old Numbers.coerce/2 function) which is now used underwater when coercion should happen.
  • 2.0.3 Improving documentation.
  • 2.0.2 Adding many tests.
  • 2.0.1 Fixing error message that is shown when conversion to float is not possible to use the Inspect protocol.
  • 2.0.0 Breaking change, mul -> mult.
  • 1.0.0 First Stable Version.

elixir-number's People

Contributors

dependabot-preview[bot] avatar dependabot-support avatar peaceful-james avatar qqwy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

elixir-number's Issues

Keep supporting integers/float operators in guards when operators are included

When someone calls use Numbers, overload_operators: true, this will currently replace all the Kernel's operators with the functions in the Numbers-module.

However, this will mean that operators in guards even if they are working on the built-in number types (ints and floats) will crash during compilation.
In the past I thought this was the only way, but from recently building Solution I now know that it is possible to define a function as a macro that does something else when in a guard environment (vs. the normal environment).

Elixir 1.11 and Decimal 1.9 support

Environment

  • Elixir 1.11.0-rc.0 and master
  • OTP 23

Current situation

ex_cldr_units depends on ratio to provide rational number support and of course that lib depends on numbers. On Elixir 1.11.0-rc.0, compiling generates the following messages. Which is quite surprising given that :coerce is definitely in your deps. I also note the error includes a deprecation warning for Decimal.minus/1 (replaced with Decimal.negate/1.

==> numbers
Compiling 7 files (.ex)
warning: Coerce.coerce/2 defined in application :coerce is used by the current application but the current application does not directly depend on :coerce. To fix this, you must do one of:

  1. If :coerce is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :coerce is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :coerce, you may optionally skip this warning by adding [xref: [exclude: Coerce] to your "def project" in mix.exs

Found at 4 locations:
  lib/numbers.ex:74: Numbers.add/2
  lib/numbers.ex:87: Numbers.sub/2
  lib/numbers.ex:98: Numbers.mult/2
  lib/numbers.ex:114: Numbers.div/2

warning: Coerce.defcoercion/3 defined in application :coerce is used by the current application but the current application does not directly depend on :coerce. To fix this, you must do one of:

  1. If :coerce is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :coerce is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :coerce, you may optionally skip this warning by adding [xref: [exclude: Coerce] to your "def project" in mix.exs

Found at 3 locations:
  lib/numbers/implementations/decimal.ex:42
  lib/numbers/implementations/decimal.ex:48
  lib/numbers/implementations/float.ex:40

warning: Coerce.CompileError.exception/1 defined in application :coerce is used by the current application but the current application does not directly depend on :coerce. To fix this, you must do one of:

  1. If :coerce is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :coerce is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :coerce, you may optionally skip this warning by adding [xref: [exclude: Coerce.CompileError] to your "def project" in mix.exs

Found at 3 locations:
  lib/numbers/implementations/decimal.ex:42
  lib/numbers/implementations/decimal.ex:48
  lib/numbers/implementations/float.ex:40

warning: Decimal.abs/1 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:29: Numbers.Protocols.Absolute.Decimal.abs/1

warning: Decimal.add/2 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:7: Numbers.Protocols.Addition.Decimal.add/2

warning: Decimal.div/2 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:21: Numbers.Protocols.Division.Decimal.div/2

warning: Decimal.minus/1 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:25: Numbers.Protocols.Minus.Decimal.minus/1

warning: Decimal.mult/2 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:16: Numbers.Protocols.Multiplication.Decimal.mult/2

warning: Decimal.new/1 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

Found at 4 locations:
  lib/numbers/implementations/decimal.ex:8: Numbers.Protocols.Addition.Decimal.add_id/1
  lib/numbers/implementations/decimal.ex:17: Numbers.Protocols.Multiplication.Decimal.mult_id/1
  lib/numbers/implementations/decimal.ex:44: Coerce.Implementations.Decimal.Integer.coerce/2
  lib/numbers/implementations/decimal.ex:50: Coerce.Implementations.Decimal.Float.coerce/2

warning: Decimal.sub/2 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:12: Numbers.Protocols.Subtraction.Decimal.sub/2

warning: Decimal.to_float/1 defined in application :decimal is used by the current application but the current application does not directly depend on :decimal. To fix this, you must do one of:

  1. If :decimal is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :decimal is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :decimal, you may optionally skip this warning by adding [xref: [exclude: Decimal] to your "def project" in mix.exs

  lib/numbers/implementations/decimal.ex:33: Numbers.Protocols.ToFloat.Decimal.to_float/1

warning: Decimal.minus/1 is deprecated. Use Decimal.negate/1 instead
  lib/numbers/implementations/decimal.ex:25: Numbers.Protocols.Minus.Decimal.minus/1

Generated numbers app

decimal requirement specificity causes issues with other hex packages

We are trying to add a package that depends upon numbers, and are running into an issue due to the specificity of the decimal version. Currently, numbers locks to ~> 1.3.0. We are currently using 1.4.0.

So long as decimal correctly follows semver and does not break backwards compatibility with minor releases, it seems like numbers could be slightly less specific... maybe ~> 1.3? I'm not sure if there is a reason for being so specific.

Thanks!

Add a `Numbers.compare` function

It would be nice if we could use coercions in combination with a possibly overloaded MyNumberType.Compare protocol to have a comparison function that works regardless of whether you put integers, floats, decimals, rationals, etc. in your collection (which you then might call Enum.sort(my_collection, Numbers) on).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.