trusted-number 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d654dde743a279a169c51a99e165c81e6b752fba76e0a7e809cb70d6ded6a9f4
4
+ data.tar.gz: 816e752739bc7c0752bc2c58059e6406c6cc4fb960049dc13735fb93116bdddb
5
+ SHA512:
6
+ metadata.gz: d75a97abd836092f32de8848ab222fdcb3047e44d9d84de6547d809e1ad0073534a2a1056efbe8ed6f410ad30503c6e55f97fd799f3eebf53c92339d5513d2a7
7
+ data.tar.gz: 5910305e64fc6de7ef1ac80ff6fee7fb6a386b0183b1cc1d5706c8133b37e641922e07602818adba9e7a612d64342b11a4793d43108344fd7e1082cf6927e4a7
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2026-03-25
4
+
5
+ - Initial release
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # trusted-number
2
+
3
+ A trusted number is a number whose value will not change secretly.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install trusted-number
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ TODO: Write usage instructions here
14
+
15
+ ## Development
16
+
17
+ 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.
18
+
19
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
20
+
21
+ ## Contributing
22
+
23
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dvarrui/trusted-number.
24
+
25
+ ---
26
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/trusted/number`. To experiment with that code, run `bin/console` for an interactive prompt.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ require "standard/rake"
13
+
14
+ task default: %i[test standard]
data/examples/demo.rb ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../lib/trusted-number"
3
+
4
+ # ------------
5
+ puts "\n" + "=" * 10
6
+ puts "Base 2:"
7
+
8
+ bin1 = TrustedNumber.new("1.1", base: 2) # (1.5 decimal)
9
+ bin2 = TrustedNumber.new("1.1", base: 2) # (1.5 decimal)
10
+
11
+ res = bin1 + bin2
12
+ puts res
13
+ puts "Value: #{res.value}" # => "11" (3.0 en decimal)
14
+
15
+ # ------------
16
+ puts "\n" + "=" * 10
17
+ puts "Base 10"
18
+ dec1 = TrustedNumber.new("0.1")
19
+ dec2 = TrustedNumber.new("0.2")
20
+
21
+ res = dec1 + dec2
22
+ puts res
23
+ puts "Value: #{res.value}"
@@ -0,0 +1,34 @@
1
+ class TrustedNumber
2
+ def +(other)
3
+ # 1. Alinear partes decimales (rellenar con 0 a la derecha)
4
+ max_post = [@postnumber.length, other.postnumber.length].max
5
+ p1 = @postnumber.ljust(max_post, "0")
6
+ p2 = other.postnumber.ljust(max_post, "0")
7
+
8
+ # 2. Sumar postnumbers
9
+ res_post, carry = add_strings(p1, p2, @base)
10
+
11
+ # 3. Sumar prenumbers + acarreo anterior
12
+ res_pre, final_carry = add_strings(@prenumber, other.prenumber, @base, carry)
13
+ res_pre = DIGITS[final_carry] + res_pre if final_carry > 0
14
+
15
+ build_result(res_pre, res_post)
16
+ end
17
+
18
+ private
19
+
20
+ def add_strings(s1, s2, base, carry = 0)
21
+ res = []
22
+ i, j = s1.length - 1, s2.length - 1
23
+ while i >= 0 || j >= 0
24
+ v1 = (i >= 0) ? DIGITS.index(s1[i]) : 0
25
+ v2 = (j >= 0) ? DIGITS.index(s2[j]) : 0
26
+ sum = v1 + v2 + carry
27
+ res << DIGITS[sum % base]
28
+ carry = sum / base
29
+ i -= 1
30
+ j -= 1
31
+ end
32
+ [res.reverse.join, carry]
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ class TrustedNumber
2
+ def ==(other)
3
+ cond = (@base == other.base)
4
+ cond &&= (@prenumber = other.prenumber)
5
+ cond &&= (@postnumber = other.postnumber)
6
+
7
+ cond
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ class TrustedNumber
2
+ def *(other)
3
+ # Algoritmo: Multiplicar como si no hubiera puntos, luego posicionar punto
4
+ s1 = @prenumber + @postnumber
5
+ s2 = other.prenumber + other.postnumber
6
+
7
+ # Multiplicación de strings (suma de productos parciales)
8
+ res_int = multiply_strings(s1, s2, @base)
9
+
10
+ # Posicionar el punto decimal
11
+ total_decimals = @postnumber.length + other.postnumber.length
12
+
13
+ if total_decimals > 0
14
+ # Asegurar que el string sea lo bastante largo
15
+ res_int = res_int.rjust(total_decimals + 1, "0")
16
+ new_pre = res_int[0...-total_decimals]
17
+ # new_post = res_int[-total_decimals..-1]
18
+ new_post = res_int[-total_decimals..]
19
+ else
20
+ new_pre, new_post = res_int, ""
21
+ end
22
+
23
+ build_result(new_pre, new_post)
24
+ end
25
+
26
+ private
27
+
28
+ def multiply_strings(s1, s2, base)
29
+ # Multiplicación básica (Long Multiplication) carácter a carácter
30
+ product = Array.new(s1.length + s2.length, 0)
31
+
32
+ (s1.length - 1).downto(0) do |i|
33
+ (s2.length - 1).downto(0) do |j|
34
+ mul = DIGITS.index(s1[i]) * DIGITS.index(s2[j])
35
+ sum = mul + product[i + j + 1]
36
+ product[i + j + 1] = sum % base
37
+ product[i + j] += sum / base
38
+ end
39
+ end
40
+ product.map { |d| DIGITS[d] }.join.gsub(/^0+(?=\d)/, "")
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ class TrustedNumber
2
+ def -(other)
3
+ # 1. Alinear decimales
4
+ max_post = [@postnumber.length, other.postnumber.length].max
5
+ p1 = @postnumber.ljust(max_post, "0")
6
+ p2 = other.postnumber.ljust(max_post, "0")
7
+
8
+ # 2. Restar postnumbers (manejando el "pedir prestado" o borrow)
9
+ res_post, borrow = sub_strings(p1, p2, @base)
10
+
11
+ # 3. Restar prenumbers - borrow
12
+ res_pre, _ = sub_strings(@prenumber, other.prenumber, @base, borrow)
13
+
14
+ build_result(res_pre, res_post)
15
+ end
16
+
17
+ private
18
+
19
+ def sub_strings(s1, s2, base, borrow = 0)
20
+ res = ""
21
+ i, j = s1.length - 1, s2.length - 1
22
+ while i >= 0 || j >= 0
23
+ v1 = (i >= 0) ? DIGITS.index(s1[i]) : 0
24
+ v2 = ((j >= 0) ? DIGITS.index(s2[j]) : 0) + borrow
25
+ if v1 < v2
26
+ v1 += base
27
+ borrow = 1
28
+ else
29
+ borrow = 0
30
+ end
31
+ res << DIGITS[v1 - v2]
32
+ i -= 1
33
+ j -= 1
34
+ end
35
+ [res.reverse, borrow]
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TrustedNumber
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "trusted-number/version"
4
+ require_relative "trusted-number/add"
5
+ require_relative "trusted-number/equal"
6
+ require_relative "trusted-number/sub"
7
+ require_relative "trusted-number/mul"
8
+
9
+ class TrustedNumber
10
+ attr_reader :base
11
+ attr_reader :prenumber, :postnumber
12
+
13
+ DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
14
+
15
+ def initialize(number, base: 10)
16
+ @number = number
17
+ @base = base
18
+
19
+ num_str = @number.to_s.downcase.delete(" ")
20
+ pre, post = num_str.split(".")
21
+ @prenumber = pre || "0"
22
+ @postnumber = post || ""
23
+
24
+ validate_format!
25
+ end
26
+
27
+ def value
28
+ @postnumber.empty? ? @prenumber : "#{@prenumber}.#{@postnumber}"
29
+ end
30
+
31
+ def to_s
32
+ "TrustedNumber: #{value} (base: #{@base})"
33
+ end
34
+
35
+ private
36
+
37
+ def build_result(pre, post)
38
+ pre_clean = pre.gsub(/^0+(?=\d)/, "")
39
+ post_clean = post.gsub(/0+$/, "")
40
+ str = post_clean.empty? ? pre_clean : "#{pre_clean}.#{post_clean}"
41
+ TrustedNumber.new(str, base: @base)
42
+ end
43
+
44
+ def validate_format!
45
+ allowed = DIGITS[0...@base]
46
+ pattern = /\A[#{allowed}]*\z/
47
+ unless @prenumber.match?(pattern) && @postnumber.match?(pattern)
48
+ raise ArgumentError, "Caracteres inválidos para base #{@base}"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ class TrustedNumber
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trusted-number
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - David Vargas
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A trusted number is a number whose value will not change secretly.
13
+ email:
14
+ - dvarrui@proton.me
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - CHANGELOG.md
20
+ - README.md
21
+ - Rakefile
22
+ - examples/demo.rb
23
+ - lib/trusted-number.rb
24
+ - lib/trusted-number/add.rb
25
+ - lib/trusted-number/equal.rb
26
+ - lib/trusted-number/mul.rb
27
+ - lib/trusted-number/sub.rb
28
+ - lib/trusted-number/version.rb
29
+ - sig/trusted-number.rbs
30
+ homepage: https://github.com/dvarrui/trusted-number
31
+ licenses: []
32
+ metadata:
33
+ homepage_uri: https://github.com/dvarrui/trusted-number
34
+ source_code_uri: https://github.com/dvarrui/trusted-number
35
+ changelog_uri: https://github.com/dvarrui/trusted-number/blob/main/CHANGELOG.md
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 3.2.0
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.7.2
51
+ specification_version: 4
52
+ summary: A trusted number is a number whose value will not change secretly.
53
+ test_files: []