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).
|
* 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.
|
* 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: 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.
|
||||||
* 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.
|
|
||||||
|
|
||||||
## Surplus order (-s/--surplus-order)
|
## Surplus order (-s/--surplus-order)
|
||||||
|
|
||||||
|
@ -82,8 +82,7 @@
|
|||||||
<label>
|
<label>
|
||||||
Numbers:
|
Numbers:
|
||||||
<select id="selNumbers">
|
<select id="selNumbers">
|
||||||
<option value="native">Native float</option>
|
<option value="native">Native</option>
|
||||||
<option value="int">Native integer</option>
|
|
||||||
<option value="rational">Rational</option>
|
<option value="rational">Rational</option>
|
||||||
<option value="fixed" selected>Fixed</option>
|
<option value="fixed" selected>Fixed</option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -26,9 +26,6 @@ onmessage = function(evt) {
|
|||||||
if (evt.data.data.numbers === 'native') {
|
if (evt.data.data.numbers === 'native') {
|
||||||
py.pyRCV2.numbers.set_numclass(py.pyRCV2.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') {
|
if (evt.data.data.numbers === 'rational') {
|
||||||
py.pyRCV2.numbers.set_numclass(py.pyRCV2.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('--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('--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('--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('--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('--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('--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')
|
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
|
# Set settings
|
||||||
if args.numbers == 'native':
|
if args.numbers == 'native':
|
||||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Native)
|
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Native)
|
||||||
elif args.numbers == 'int':
|
|
||||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.NativeInt)
|
|
||||||
elif args.numbers == 'rational':
|
elif args.numbers == 'rational':
|
||||||
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Rational)
|
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Rational)
|
||||||
elif args.numbers == 'fixed':
|
elif args.numbers == 'fixed':
|
||||||
|
@ -23,13 +23,11 @@ __pragma__('noskip')
|
|||||||
if is_py:
|
if is_py:
|
||||||
__pragma__('skip')
|
__pragma__('skip')
|
||||||
from pyRCV2.numbers.fixed_py import Fixed, set_dps
|
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.native_py import Native
|
||||||
from pyRCV2.numbers.rational_py import Rational
|
from pyRCV2.numbers.rational_py import Rational
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else:
|
||||||
from pyRCV2.numbers.fixed_js import Fixed, set_dps
|
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.native_js import Native
|
||||||
from pyRCV2.numbers.rational_js import Rational
|
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