Remove native integers mode in preparation for more advanced rounding options
This commit is contained in:
parent
1b74e41695
commit
7b52f8f06d
@ -47,10 +47,7 @@ This dropdown allows you to select how numbers (vote totals, etc.) are represent
|
||||
|
||||
* Fixed: Numbers are represented as fixed-precision decimals, up to a certain number of decimal places (default: 5).
|
||||
* Rational: Numbers are represented exactly as fractions, resulting in the elimination of rounding error, but increasing computational complexity when the number of surplus transfers is very large.
|
||||
* Native float: Numbers are represented as floating-point numbers. This is fast, but not recommended as unexpectedly large rounding errors may be introduced in some circumstances.
|
||||
* Native int: Numbers are represented as integers. Fractions are discarded.
|
||||
|
||||
Note that, during some calculations, in order to reduce rounding errors, ballot weights and intermediate may be represented internally as fractions irrespective of this option.
|
||||
* Native: Numbers are represented as native integers or floating-point numbers. This is fast, but not recommended as unexpectedly large rounding errors may be introduced in some circumstances.
|
||||
|
||||
## Surplus order (-s/--surplus-order)
|
||||
|
||||
|
@ -82,8 +82,7 @@
|
||||
<label>
|
||||
Numbers:
|
||||
<select id="selNumbers">
|
||||
<option value="native">Native float</option>
|
||||
<option value="int">Native integer</option>
|
||||
<option value="native">Native</option>
|
||||
<option value="rational">Rational</option>
|
||||
<option value="fixed" selected>Fixed</option>
|
||||
</select>
|
||||
|
@ -26,9 +26,6 @@ onmessage = function(evt) {
|
||||
if (evt.data.data.numbers === 'native') {
|
||||
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Native);
|
||||
}
|
||||
if (evt.data.data.numbers === 'int') {
|
||||
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.NativeInt);
|
||||
}
|
||||
if (evt.data.data.numbers === 'rational') {
|
||||
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Rational);
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ def add_parser(subparsers):
|
||||
parser.add_argument('--quota-criterion', '-c', choices=['geq', 'gt'], default='geq', help='quota criterion (default: geq)')
|
||||
parser.add_argument('--prog-quota', action='store_true', help='progressively reducing quota')
|
||||
parser.add_argument('--no-bulk-election', action='store_true', help='disable bulk election unless absolutely required')
|
||||
parser.add_argument('--numbers', '-n', choices=['fixed', 'rational', 'int', 'native'], default='fixed', help='numbers mode (default: fixed)')
|
||||
parser.add_argument('--numbers', '-n', choices=['fixed', 'rational', 'native'], default='fixed', help='numbers mode (default: fixed)')
|
||||
parser.add_argument('--decimals', type=int, default=5, help='decimal places if --numbers fixed (default: 5)')
|
||||
parser.add_argument('--round-votes', type=int, help='round votes to specified decimal places')
|
||||
parser.add_argument('--round-weights', type=int, help='round ballot weights to specified decimal places')
|
||||
parser.add_argument('--surplus-order', '-s', choices=['size', 'order'], default='size', help='whether to distribute surpluses by size or by order of election (default: size)')
|
||||
parser.add_argument('--method', '-m', choices=['wig', 'uig', 'eg', 'wright'], default='wig', help='method of surpluses and exclusions (default: wig - weighted inclusive Gregory)')
|
||||
parser.add_argument('--transferable-only', action='store_true', help='examine only transferable papers during surplus distributions')
|
||||
@ -69,8 +71,6 @@ def main(args):
|
||||
# Set settings
|
||||
if args.numbers == 'native':
|
||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Native)
|
||||
elif args.numbers == 'int':
|
||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.NativeInt)
|
||||
elif args.numbers == 'rational':
|
||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Rational)
|
||||
elif args.numbers == 'fixed':
|
||||
|
@ -23,13 +23,11 @@ __pragma__('noskip')
|
||||
if is_py:
|
||||
__pragma__('skip')
|
||||
from pyRCV2.numbers.fixed_py import Fixed, set_dps
|
||||
from pyRCV2.numbers.int_py import NativeInt
|
||||
from pyRCV2.numbers.native_py import Native
|
||||
from pyRCV2.numbers.rational_py import Rational
|
||||
__pragma__('noskip')
|
||||
else:
|
||||
from pyRCV2.numbers.fixed_js import Fixed, set_dps
|
||||
from pyRCV2.numbers.int_js import NativeInt
|
||||
from pyRCV2.numbers.native_js import Native
|
||||
from pyRCV2.numbers.rational_js import Rational
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
# pyRCV2: Preferential vote counting
|
||||
# Copyright © 2020 Lee Yingtong Li (RunasSudo)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
class NativeInt:
|
||||
"""
|
||||
Wrapper for JS integers
|
||||
"""
|
||||
|
||||
def __init__(self, val):
|
||||
if isinstance(val, NativeInt):
|
||||
self.impl = val.impl
|
||||
else:
|
||||
self.impl = Math.floor(parseFloat(val))
|
||||
|
||||
def pp(self, dp):
|
||||
"""Pretty print to specified number of decimal places"""
|
||||
return self.impl.toFixed(0)
|
||||
|
||||
def to_rational(self):
|
||||
"""Convert to an instance of Rational"""
|
||||
from pyRCV2.numbers import Rational
|
||||
return Rational(self.impl)
|
||||
|
||||
def __add__(self, other):
|
||||
return NativeInt(self.impl + other.impl)
|
||||
def __sub__(self, other):
|
||||
return NativeInt(self.impl - other.impl)
|
||||
def __mul__(self, other):
|
||||
return NativeInt(self.impl * other.impl)
|
||||
def __div__(self, other):
|
||||
return NativeInt(self.impl / other.impl)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.impl == other.impl
|
||||
def __gt__(self, other):
|
||||
return self.impl > other.impl
|
||||
def __ge__(self, other):
|
||||
return self.impl >= other.impl
|
||||
def __lt__(self, other):
|
||||
return self.impl < other.impl
|
||||
def __le__(self, other):
|
||||
return self.impl <= other.impl
|
||||
|
||||
def __floor__(self):
|
||||
return NativeInt(Math.floor(self.impl))
|
@ -1,78 +0,0 @@
|
||||
# pyRCV2: Preferential vote counting
|
||||
# Copyright © 2020 Lee Yingtong Li (RunasSudo)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import math
|
||||
|
||||
class NativeInt:
|
||||
"""
|
||||
Wrapper for Python int
|
||||
"""
|
||||
|
||||
def __init__(self, val):
|
||||
if isinstance(val, NativeInt):
|
||||
self.impl = val.impl
|
||||
else:
|
||||
self.impl = int(val)
|
||||
|
||||
def pp(self, dp):
|
||||
"""Pretty print to specified number of decimal places"""
|
||||
return str(self.impl)
|
||||
|
||||
def to_rational(self):
|
||||
"""Convert to an instance of Rational"""
|
||||
from pyRCV2.numbers import Rational
|
||||
return Rational(self.impl)
|
||||
|
||||
def __add__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return NativeInt(self.impl + other.impl)
|
||||
def __sub__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return NativeInt(self.impl - other.impl)
|
||||
def __mul__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return NativeInt(self.impl * other.impl)
|
||||
def __truediv__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return NativeInt(self.impl / other.impl)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return self.impl == other.impl
|
||||
def __gt__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return self.impl > other.impl
|
||||
def __ge__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return self.impl >= other.impl
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return self.impl < other.impl
|
||||
def __le__(self, other):
|
||||
if not isinstance(other, NativeInt):
|
||||
raise ValueError('Attempt to operate on incompatible types')
|
||||
return self.impl <= other.impl
|
||||
|
||||
def __floor__(self):
|
||||
return NativeInt(math.floor(self.impl))
|
Reference in New Issue
Block a user