├── .github ├── dependabot.yml └── workflows │ ├── package.yml │ └── test.yml ├── .gitignore ├── BSDL ├── COPYING ├── Gemfile ├── LEGAL ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── lib ├── mathn.rb └── mathn │ ├── complex.rb │ └── rational.rb ├── mathn.gemspec ├── rakelib └── epoch.rake └── test ├── lib └── helper.rb └── test_mathn.rb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | -------------------------------------------------------------------------------- /.github/workflows/package.yml: -------------------------------------------------------------------------------- 1 | name: package 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ruby-versions: 7 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 8 | with: 9 | engine: cruby 10 | min_version: 2.5 11 | 12 | build: 13 | needs: ruby-versions 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | ruby: [ '${{ needs.ruby-versions.outputs.latest }}', 'head' ] 18 | os: [ ubuntu-latest, macos-latest, windows-latest ] 19 | exclude: 20 | - { ruby: head, os: windows-latest } 21 | steps: 22 | - name: git config 23 | run: | 24 | git config --global core.autocrlf false 25 | git config --global core.eol lf 26 | git config --global advice.detachedHead 0 27 | - uses: actions/checkout@v4 28 | - name: Set up Ruby 29 | uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: ${{ matrix.ruby }} 32 | - name: Install dependencies 33 | run: bundle install 34 | - name: Package 35 | id: package 36 | run: | 37 | rake build 38 | pkg="${GITHUB_REPOSITORY#*/}-${RUNNING_OS%-*}" 39 | RUBY_VERSION=${{matrix.ruby}} 40 | if [ "$RUBY_VERSION" = head ]; then 41 | pkg=$pkg-$RUBY_VERSION 42 | fi 43 | echo "pkg=$pkg" >> $GITHUB_OUTPUT 44 | env: 45 | RUNNING_OS: ${{matrix.os}} 46 | shell: bash 47 | - name: Upload package 48 | uses: actions/upload-artifact@v4 49 | with: 50 | path: pkg/* 51 | name: ${{steps.package.outputs.pkg}} 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ruby-versions: 7 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 8 | with: 9 | engine: cruby 10 | min_version: 2.5 11 | 12 | build: 13 | needs: ruby-versions 14 | name: build (${{ matrix.ruby }} / ${{ matrix.os }}) 15 | strategy: 16 | matrix: 17 | ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} 18 | os: [ ubuntu-latest, macos-latest, windows-latest ] 19 | exclude: 20 | - { os: macos-latest, ruby: '2.5' } 21 | include: 22 | - { os: macos-13, ruby: '2.5' } 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Set up Ruby 27 | uses: ruby/setup-ruby@v1 28 | with: 29 | ruby-version: ${{ matrix.ruby }} 30 | - name: Install dependencies 31 | run: bundle install 32 | - name: Run test 33 | run: bundle exec rake 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.dll 13 | -------------------------------------------------------------------------------- /BSDL: -------------------------------------------------------------------------------- 1 | Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Ruby is copyrighted free software by Yukihiro Matsumoto . 2 | You can redistribute it and/or modify it under either the terms of the 3 | 2-clause BSDL (see the file BSDL), or the conditions below: 4 | 5 | 1. You may make and give away verbatim copies of the source form of the 6 | software without restriction, provided that you duplicate all of the 7 | original copyright notices and associated disclaimers. 8 | 9 | 2. You may modify your copy of the software in any way, provided that 10 | you do at least ONE of the following: 11 | 12 | a. place your modifications in the Public Domain or otherwise 13 | make them Freely Available, such as by posting said 14 | modifications to Usenet or an equivalent medium, or by allowing 15 | the author to include your modifications in the software. 16 | 17 | b. use the modified software only within your corporation or 18 | organization. 19 | 20 | c. give non-standard binaries non-standard names, with 21 | instructions on where to get the original software distribution. 22 | 23 | d. make other distribution arrangements with the author. 24 | 25 | 3. You may distribute the software in object code or binary form, 26 | provided that you do at least ONE of the following: 27 | 28 | a. distribute the binaries and library files of the software, 29 | together with instructions (in the manual page or equivalent) 30 | on where to get the original distribution. 31 | 32 | b. accompany the distribution with the machine-readable source of 33 | the software. 34 | 35 | c. give non-standard binaries non-standard names, with 36 | instructions on where to get the original software distribution. 37 | 38 | d. make other distribution arrangements with the author. 39 | 40 | 4. You may modify and include the part of the software into any other 41 | software (possibly commercial). But some files in the distribution 42 | are not written by the author, so that they are not under these terms. 43 | 44 | For the list of those files and their copying conditions, see the 45 | file LEGAL. 46 | 47 | 5. The scripts and library files supplied as input to or produced as 48 | output from the software do not automatically fall under the 49 | copyright of the software, but belong to whomever generated them, 50 | and may be sold commercially, and may be aggregated with this 51 | software. 52 | 53 | 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 54 | IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 55 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 | PURPOSE. 57 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem "cmath" 6 | group :development do 7 | gem "bundler" 8 | gem "rake" 9 | gem "test-unit" 10 | gem "test-unit-ruby-core" 11 | end 12 | -------------------------------------------------------------------------------- /LEGAL: -------------------------------------------------------------------------------- 1 | # -*- rdoc -*- 2 | 3 | = LEGAL NOTICE INFORMATION 4 | -------------------------- 5 | 6 | All the files in this distribution are covered under either the Ruby's 7 | license (see the file COPYING) or public-domain except some files 8 | mentioned below. 9 | 10 | == MIT License 11 | >>> 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | == Old-style BSD license 32 | >>> 33 | Redistribution and use in source and binary forms, with or without 34 | modification, are permitted provided that the following conditions 35 | are met: 36 | 1. Redistributions of source code must retain the above copyright 37 | notice, this list of conditions and the following disclaimer. 38 | 2. Redistributions in binary form must reproduce the above copyright 39 | notice, this list of conditions and the following disclaimer in the 40 | documentation and/or other materials provided with the distribution. 41 | 3. Neither the name of the University nor the names of its contributors 42 | may be used to endorse or promote products derived from this software 43 | without specific prior written permission. 44 | 45 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 | SUCH DAMAGE. 56 | 57 | IMPORTANT NOTE:: 58 | 59 | From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change 60 | paragraph 3 above is now null and void. 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mathn 2 | 3 | [![Build Status](https://travis-ci.org/ruby/mathn.svg?branch=master)](https://travis-ci.org/ruby/mathn) 4 | 5 | mathn serves to make mathematical operations more precise in Ruby and to integrate other mathematical standard libraries. 6 | 7 | Without mathn: 8 | 9 | ```ruby 10 | 3 / 2 => 1 # Integer 11 | ``` 12 | 13 | With mathn: 14 | 15 | ```ruby 16 | 3 / 2 => 3/2 # Rational 17 | ``` 18 | 19 | mathn keeps value in exact terms. 20 | 21 | Without mathn: 22 | 23 | ```ruby 24 | 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 18 25 | ``` 26 | 27 | With mathn: 28 | 29 | ```ruby 30 | 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 20 31 | ``` 32 | 33 | ## Global Behavioral changes 34 | 35 | While older version of 'mathn', just by required, caused changes to 36 | the behavior (and even the types) of operations on classes like 37 | Integer newer `mathn` introduces the refinements `Math::N`, and you 38 | have to enable it. 39 | 40 | Before ruby 2.5, `mathn` was part of the ruby standard library. It was 41 | was [deprecated in ruby 2.2.0](https://github.com/ruby/ruby/blob/v2_2_0/NEWS#stdlib-compatibility-issues-excluding-feature-bug-fixes), 42 | and [removed from ruby 2.5.0](https://github.com/ruby/ruby/blob/ruby_2_5/NEWS#stdlib-compatibility-issues-excluding-feature-bug-fixes). 43 | In order to use the library with a current version of ruby, 44 | you must install it as a gem. 45 | 46 | ## Installation 47 | 48 | Add this line to your application's Gemfile: 49 | 50 | ```ruby 51 | gem 'mathn' 52 | ``` 53 | 54 | And then execute: 55 | 56 | $ bundle 57 | 58 | Or install it yourself as: 59 | 60 | $ gem install mathn 61 | 62 | ## Usage 63 | 64 | ```ruby 65 | require 'mathn' 66 | using Math::N 67 | ``` 68 | 69 | ## Development 70 | 71 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 72 | 73 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 74 | 75 | ## Contributing 76 | 77 | Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/mathn. 78 | 79 | 80 | ## License 81 | 82 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 83 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test/lib" 6 | t.ruby_opts << "-rhelper" 7 | t.test_files = FileList['test/**/test_*.rb'] 8 | end 9 | 10 | task "build" => "date_epoch" 11 | task "date_epoch" do 12 | ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp 13 | end 14 | 15 | ENV['RUBYOPT'] = "-w" 16 | 17 | task :default => [:test] 18 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "mathn" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/mathn.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ## 4 | # = mathn 5 | # 6 | # mathn serves to make mathematical operations more precise in Ruby 7 | # and to integrate other mathematical standard libraries. 8 | # 9 | # Without mathn: 10 | # 11 | # using Math::N 12 | # 3 / 2 => 1 # Integer 13 | # 14 | # With mathn: 15 | # 16 | # using Math::N 17 | # 3 / 2 => 3/2 # Rational 18 | # 19 | # mathn keeps value in exact terms. 20 | # 21 | # Without mathn: 22 | # 23 | # 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 18 24 | # 25 | # With mathn: 26 | # 27 | # using Math::N 28 | # 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 20 29 | # 30 | # 31 | # When you require 'mathn', the libraries for CMath is also loaded. 32 | # 33 | # == Copyright 34 | # 35 | # Author: Keiju ISHITSUKA (SHL Japan Inc.) 36 | 37 | require "cmath" 38 | require_relative "mathn/complex" 39 | require_relative "mathn/rational" 40 | 41 | module Math::N 42 | # The version string 43 | VERSION = "0.2.0" 44 | 45 | refine ::Numeric do 46 | alias canonicalize itself 47 | end 48 | 49 | using self # for canonicalize methods 50 | 51 | def +(other) super.canonicalize end 52 | def -(other) super.canonicalize end 53 | def *(other) super.canonicalize end 54 | def /(other) super.canonicalize end 55 | def quo(other) super.canonicalize end 56 | def **(other) super.canonicalize end 57 | 58 | # Transplant per methods. 59 | canon = public_instance_methods(false).map do |n, h| 60 | [n, instance_method(n)] 61 | end 62 | for klass in [::Integer, ::Rational, ::Complex] 63 | refine klass do 64 | canon.each {|n, m| define_method(n, m)} 65 | end 66 | end 67 | 68 | ## 69 | # Enhance Integer's division to return more precise values from 70 | # mathematical expressions. 71 | refine ::Integer do 72 | 73 | ## 74 | # +/+ defines the Rational division for Integer. 75 | # 76 | # require 'mathn' 77 | # 2/3*3 # => 0 78 | # (2**72) / ((2**70) * 3) # => 1 79 | # 80 | # using Math::N 81 | # 2/3*3 # => 2 82 | # (2**72) / ((2**70) * 3) # => 4/3 83 | alias / quo 84 | end 85 | 86 | math = refine ::Math do 87 | module_function 88 | 89 | ## 90 | # Computes the square root of +a+. It makes use of Complex and 91 | # Rational to have no rounding errors if possible. 92 | # 93 | # Standard Math module behaviour: 94 | # Math.sqrt(4/9) # => 0.0 95 | # Math.sqrt(4.0/9.0) # => 0.6666666666666666 96 | # Math.sqrt(- 4/9) # => Errno::EDOM: Numerical argument out of domain - sqrt 97 | # 98 | # When using 'Math::N', this is changed to: 99 | # 100 | # require 'mathn' 101 | # using Math::N 102 | # Math.sqrt(4/9) # => 2/3 103 | # Math.sqrt(4.0/9.0) # => 0.666666666666666 104 | # Math.sqrt(- 4/9) # => Complex(0, 2/3) 105 | 106 | def sqrt(a) 107 | return super unless a.respond_to?(:negative?) 108 | return a if a.respond_to?(:nan?) and a.nan? 109 | negative = a.negative? 110 | 111 | # Compute square root of a non negative number. 112 | case a 113 | when Float 114 | a = super(a.abs) 115 | when Rational 116 | a = sqrt(a.numerator.abs).quo sqrt(a.denominator.abs) 117 | else 118 | rt = Integer.sqrt(a = a.abs) 119 | a = rt * rt == a ? rt : super(a) 120 | end 121 | negative ? Complex(0, a) : a 122 | end 123 | 124 | ## 125 | # Computes the cubic root of +a+. It makes use of Complex and 126 | # Rational to have no rounding errors if possible. 127 | # 128 | # Standard Math module behaviour: 129 | # Math.cbrt(8/27) # => 0.0 130 | # Math.cbrt(8.0/27.0) # => 0.666666666666666 131 | # Math.cbrt(- 8/27) # => -1.0 132 | # 133 | # When using 'Math::N', this is changed to: 134 | # 135 | # require 'mathn' 136 | # using Math::N 137 | # Math.cbrt(8/27) # => (2/3) 138 | # Math.cbrt(8.0/27.0) # => 0.666666666666666 139 | # Math.cbrt(-8/27) # => (-2/3) 140 | 141 | def cbrt(a) 142 | case a 143 | when Integer 144 | rt = super 145 | rt ** 3 == a ? Integer(rt) : rt 146 | when Rational 147 | cbrt(a.numerator).quo cbrt(a.denominator) 148 | when Complex 149 | a ** (1/3r) 150 | else 151 | super 152 | end 153 | end 154 | end 155 | 156 | # Transplant module functions. 157 | refine ::Math.singleton_class do 158 | math.private_instance_methods(false).each do |m| 159 | next unless math.respond_to?(m) 160 | public define_method(m, Math.instance_method(m)) 161 | end 162 | end 163 | end 164 | -------------------------------------------------------------------------------- /lib/mathn/complex.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # mathn/complex 4 | module Math::N 5 | refine ::Complex do 6 | def canonicalize 7 | if imag.zero? 8 | real.canonicalize 9 | else 10 | self 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/mathn/rational.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # mathn/rational 4 | module Math::N 5 | refine ::Rational do 6 | def canonicalize 7 | if denominator == 1 8 | numerator.canonicalize 9 | else 10 | self 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /mathn.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | version = File.read(File.join(__dir__, "lib/mathn.rb"))[/^ *VERSION *= *"\K.*?(?=")/] 3 | 4 | Gem::Specification.new do |spec| 5 | spec.name = "mathn" 6 | spec.version = version 7 | spec.authors = ["Keiju ISHITSUKA"] 8 | spec.email = ["keiju@ishitsuka.com"] 9 | 10 | spec.summary = "Deprecated library that extends math operations." 11 | spec.description = "Deprecated library that extends math operations." 12 | spec.homepage = "https://github.com/ruby/mathn" 13 | spec.license = "BSD-2-Clause" 14 | 15 | gemspec = File.basename(__FILE__) 16 | spec.files = Dir.chdir(__dir__) do 17 | `git ls-files -z`.split("\x0").reject do |f| 18 | f == gemspec or 19 | f.match(%r{\A(?:bin|test|spec|features|rakelib)/|\A(?:Gem|Rake)file|\.(?:git|travis)}) 20 | end 21 | end 22 | spec.bindir = "exe" 23 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 24 | spec.required_ruby_version = ">= 2.5" 25 | spec.require_paths = ["lib"] 26 | 27 | spec.add_dependency "cmath" 28 | end 29 | -------------------------------------------------------------------------------- /rakelib/epoch.rake: -------------------------------------------------------------------------------- 1 | task "build" => "date_epoch" 2 | 3 | task "date_epoch" do 4 | ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp 5 | end 6 | -------------------------------------------------------------------------------- /test/lib/helper.rb: -------------------------------------------------------------------------------- 1 | require "test/unit" 2 | require "core_assertions" 3 | 4 | Test::Unit::TestCase.include Test::Unit::CoreAssertions 5 | -------------------------------------------------------------------------------- /test/test_mathn.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: false 2 | require 'test/unit' 3 | require 'mathn' 4 | 5 | module TestMathn 6 | HALF = 1/2r 7 | 8 | class WithoutMathn < Test::Unit::TestCase 9 | def test_plus 10 | assert_kind_of(Rational, (1/2r)+(1/2r)) 11 | assert_kind_of(Complex, (1-1i)+1i) 12 | end 13 | 14 | def test_minus 15 | assert_kind_of(Rational, (1/2r)-(1/2r)) 16 | assert_kind_of(Complex, (1+1i)-1i) 17 | end 18 | 19 | def test_mul 20 | assert_kind_of(Rational, 1/2r*2) 21 | assert_equal(0, 1/2*2) 22 | 23 | x = (1+1i)*(1-1i) 24 | assert_kind_of(Complex, x) 25 | assert_equal(2, x) 26 | end 27 | 28 | def test_div 29 | assert_kind_of(Rational, (4/3r)/(2/3r)) 30 | assert_equal(0, (2/3)/(4/3)) 31 | 32 | x = (2+2i)/(1+1i) 33 | assert_kind_of(Complex, x) 34 | assert_equal(2, x) 35 | end 36 | end 37 | 38 | class WithMathn < Test::Unit::TestCase 39 | using Math::N 40 | 41 | def test_plus 42 | assert_kind_of(Integer, (1/2r)+(1/2r)) 43 | assert_kind_of(Integer, (1-1i)+1i) 44 | end 45 | 46 | def test_minus 47 | assert_kind_of(Integer, (1/2r)-(1/2r)) 48 | assert_kind_of(Integer, (1+1i)-1i) 49 | end 50 | 51 | def test_mul 52 | assert_kind_of(Integer, 1/2r*2) 53 | assert_equal(1, 1/2*2) 54 | 55 | x = (1+1i)*(1-1i) 56 | assert_kind_of(Integer, x) 57 | assert_equal(2, x) 58 | end 59 | 60 | def test_div 61 | assert_kind_of(Integer, (4/3r)/(2/3r)) 62 | assert_equal(1/2r, (2/3)/(4/3)) 63 | 64 | x = (2+2i)/(1+1i) 65 | assert_kind_of(Integer, x) 66 | assert_equal(2, x) 67 | end 68 | 69 | def test_power 70 | assert_equal(1, 1**2) 71 | assert_kind_of(Integer, (1 << 126)**2) 72 | assert_equal(1, Complex(0,1)**4) 73 | assert_equal(1i, Complex(0,1)**5) 74 | end 75 | 76 | def test_quo 77 | assert_equal(1/2r, 1.quo(2) , '[ruby-core:41575]') 78 | end 79 | 80 | def test_floor 81 | assert_equal( 2, ( 13/5).floor) 82 | assert_equal( 2, ( 5/2).floor) 83 | assert_equal( 2, ( 12/5).floor) 84 | assert_equal(-3, (-12/5).floor) 85 | assert_equal(-3, ( -5/2).floor) 86 | assert_equal(-3, (-13/5).floor) 87 | 88 | assert_equal( 2, ( 13/5).floor(0)) 89 | assert_equal( 2, ( 5/2).floor(0)) 90 | assert_equal( 2, ( 12/5).floor(0)) 91 | assert_equal(-3, (-12/5).floor(0)) 92 | assert_equal(-3, ( -5/2).floor(0)) 93 | assert_equal(-3, (-13/5).floor(0)) 94 | 95 | assert_equal(( 13/5), ( 13/5).floor(2)) 96 | assert_equal(( 5/2), ( 5/2).floor(2)) 97 | assert_equal(( 12/5), ( 12/5).floor(2)) 98 | assert_equal((-12/5), (-12/5).floor(2)) 99 | assert_equal(( -5/2), ( -5/2).floor(2)) 100 | assert_equal((-13/5), (-13/5).floor(2)) 101 | end 102 | 103 | def test_ceil 104 | assert_equal( 3, ( 13/5).ceil) 105 | assert_equal( 3, ( 5/2).ceil) 106 | assert_equal( 3, ( 12/5).ceil) 107 | assert_equal(-2, (-12/5).ceil) 108 | assert_equal(-2, ( -5/2).ceil) 109 | assert_equal(-2, (-13/5).ceil) 110 | 111 | assert_equal( 3, ( 13/5).ceil(0)) 112 | assert_equal( 3, ( 5/2).ceil(0)) 113 | assert_equal( 3, ( 12/5).ceil(0)) 114 | assert_equal(-2, (-12/5).ceil(0)) 115 | assert_equal(-2, ( -5/2).ceil(0)) 116 | assert_equal(-2, (-13/5).ceil(0)) 117 | 118 | assert_equal(( 13/5), ( 13/5).ceil(2)) 119 | assert_equal(( 5/2), ( 5/2).ceil(2)) 120 | assert_equal(( 12/5), ( 12/5).ceil(2)) 121 | assert_equal((-12/5), (-12/5).ceil(2)) 122 | assert_equal(( -5/2), ( -5/2).ceil(2)) 123 | assert_equal((-13/5), (-13/5).ceil(2)) 124 | end 125 | 126 | def test_truncate 127 | assert_equal( 2, ( 13/5).truncate) 128 | assert_equal( 2, ( 5/2).truncate) 129 | assert_equal( 2, ( 12/5).truncate) 130 | assert_equal(-2, (-12/5).truncate) 131 | assert_equal(-2, ( -5/2).truncate) 132 | assert_equal(-2, (-13/5).truncate) 133 | 134 | assert_equal( 2, ( 13/5).truncate(0)) 135 | assert_equal( 2, ( 5/2).truncate(0)) 136 | assert_equal( 2, ( 12/5).truncate(0)) 137 | assert_equal(-2, (-12/5).truncate(0)) 138 | assert_equal(-2, ( -5/2).truncate(0)) 139 | assert_equal(-2, (-13/5).truncate(0)) 140 | 141 | assert_equal(( 13/5), ( 13/5).truncate(2)) 142 | assert_equal(( 5/2), ( 5/2).truncate(2)) 143 | assert_equal(( 12/5), ( 12/5).truncate(2)) 144 | assert_equal((-12/5), (-12/5).truncate(2)) 145 | assert_equal(( -5/2), ( -5/2).truncate(2)) 146 | assert_equal((-13/5), (-13/5).truncate(2)) 147 | end 148 | 149 | def test_round 150 | assert_equal( 3, ( 13/5).round) 151 | assert_equal( 3, ( 5/2).round) 152 | assert_equal( 2, ( 12/5).round) 153 | assert_equal(-2, (-12/5).round) 154 | assert_equal(-3, ( -5/2).round) 155 | assert_equal(-3, (-13/5).round) 156 | 157 | assert_equal( 3, ( 13/5).round(0)) 158 | assert_equal( 3, ( 5/2).round(0)) 159 | assert_equal( 2, ( 12/5).round(0)) 160 | assert_equal(-2, (-12/5).round(0)) 161 | assert_equal(-3, ( -5/2).round(0)) 162 | assert_equal(-3, (-13/5).round(0)) 163 | 164 | assert_equal(( 13/5), ( 13/5).round(2)) 165 | assert_equal(( 5/2), ( 5/2).round(2)) 166 | assert_equal(( 12/5), ( 12/5).round(2)) 167 | assert_equal((-12/5), (-12/5).round(2)) 168 | assert_equal(( -5/2), ( -5/2).round(2)) 169 | assert_equal((-13/5), (-13/5).round(2)) 170 | 171 | assert_equal( 3, ( 13/5).round(half: :even)) 172 | assert_equal( 2, ( 5/2).round(half: :even)) 173 | assert_equal( 2, ( 12/5).round(half: :even)) 174 | assert_equal(-2, (-12/5).round(half: :even)) 175 | assert_equal(-2, ( -5/2).round(half: :even)) 176 | assert_equal(-3, (-13/5).round(half: :even)) 177 | 178 | assert_equal( 3, ( 13/5).round(0, half: :even)) 179 | assert_equal( 2, ( 5/2).round(0, half: :even)) 180 | assert_equal( 2, ( 12/5).round(0, half: :even)) 181 | assert_equal(-2, (-12/5).round(0, half: :even)) 182 | assert_equal(-2, ( -5/2).round(0, half: :even)) 183 | assert_equal(-3, (-13/5).round(0, half: :even)) 184 | 185 | assert_equal(( 13/5), ( 13/5).round(2, half: :even)) 186 | assert_equal(( 5/2), ( 5/2).round(2, half: :even)) 187 | assert_equal(( 12/5), ( 12/5).round(2, half: :even)) 188 | assert_equal((-12/5), (-12/5).round(2, half: :even)) 189 | assert_equal(( -5/2), ( -5/2).round(2, half: :even)) 190 | assert_equal((-13/5), (-13/5).round(2, half: :even)) 191 | 192 | assert_equal( 3, ( 13/5).round(half: :up)) 193 | assert_equal( 3, ( 5/2).round(half: :up)) 194 | assert_equal( 2, ( 12/5).round(half: :up)) 195 | assert_equal(-2, (-12/5).round(half: :up)) 196 | assert_equal(-3, ( -5/2).round(half: :up)) 197 | assert_equal(-3, (-13/5).round(half: :up)) 198 | 199 | assert_equal( 3, ( 13/5).round(0, half: :up)) 200 | assert_equal( 3, ( 5/2).round(0, half: :up)) 201 | assert_equal( 2, ( 12/5).round(0, half: :up)) 202 | assert_equal(-2, (-12/5).round(0, half: :up)) 203 | assert_equal(-3, ( -5/2).round(0, half: :up)) 204 | assert_equal(-3, (-13/5).round(0, half: :up)) 205 | 206 | assert_equal(( 13/5), ( 13/5).round(2, half: :up)) 207 | assert_equal(( 5/2), ( 5/2).round(2, half: :up)) 208 | assert_equal(( 12/5), ( 12/5).round(2, half: :up)) 209 | assert_equal((-12/5), (-12/5).round(2, half: :up)) 210 | assert_equal(( -5/2), ( -5/2).round(2, half: :up)) 211 | assert_equal((-13/5), (-13/5).round(2, half: :up)) 212 | 213 | assert_equal( 3, ( 13/5).round(half: :down)) 214 | assert_equal( 2, ( 5/2).round(half: :down)) 215 | assert_equal( 2, ( 12/5).round(half: :down)) 216 | assert_equal(-2, (-12/5).round(half: :down)) 217 | assert_equal(-2, ( -5/2).round(half: :down)) 218 | assert_equal(-3, (-13/5).round(half: :down)) 219 | 220 | assert_equal( 3, ( 13/5).round(0, half: :down)) 221 | assert_equal( 2, ( 5/2).round(0, half: :down)) 222 | assert_equal( 2, ( 12/5).round(0, half: :down)) 223 | assert_equal(-2, (-12/5).round(0, half: :down)) 224 | assert_equal(-2, ( -5/2).round(0, half: :down)) 225 | assert_equal(-3, (-13/5).round(0, half: :down)) 226 | 227 | assert_equal(( 13/5), ( 13/5).round(2, half: :down)) 228 | assert_equal(( 5/2), ( 5/2).round(2, half: :down)) 229 | assert_equal(( 12/5), ( 12/5).round(2, half: :down)) 230 | assert_equal((-12/5), (-12/5).round(2, half: :down)) 231 | assert_equal(( -5/2), ( -5/2).round(2, half: :down)) 232 | assert_equal((-13/5), (-13/5).round(2, half: :down)) 233 | end 234 | 235 | def test_rational 236 | assert_equal(-5, "-5".to_r) 237 | assert_equal(1, "5/5".to_r) 238 | assert_equal(5, "5e0".to_r) 239 | end 240 | end 241 | end 242 | --------------------------------------------------------------------------------