refacto: Long → BigInteger

API BREAK
It's okay, we're still in 0.x
pull/4/head
Dominique Merle 3 years ago
parent b8739d61f7
commit 13ae5615ab

@ -1,5 +1,6 @@
package fr.mieuxvoter.mj; package fr.mieuxvoter.mj;
import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -24,7 +25,7 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface {
public ResultInterface deliberate(TallyInterface tally) { public ResultInterface deliberate(TallyInterface tally) {
ProposalTallyInterface[] tallies = tally.getProposalsTallies(); ProposalTallyInterface[] tallies = tally.getProposalsTallies();
Long amountOfJudges = tally.getAmountOfJudges(); BigInteger amountOfJudges = tally.getAmountOfJudges();
Integer amountOfProposals = tally.getAmountOfProposals(); Integer amountOfProposals = tally.getAmountOfProposals();
Result result = new Result(); Result result = new Result();
@ -69,13 +70,13 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface {
return result; return result;
} }
public String computeScore(ProposalTallyInterface tally, Long amountOfJudges) { public String computeScore(ProposalTallyInterface tally, BigInteger amountOfJudges) {
return computeScore(tally, amountOfJudges, true, false); return computeScore(tally, amountOfJudges, true, false);
} }
public String computeScore( public String computeScore(
ProposalTallyInterface tally, ProposalTallyInterface tally,
Long amountOfJudges, BigInteger amountOfJudges,
Boolean favorContestation, Boolean favorContestation,
Boolean onlyNumbers Boolean onlyNumbers
) { ) {
@ -99,15 +100,19 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface {
"%0"+digitsForGrade+"d", "%0"+digitsForGrade+"d",
analysis.getMedianGrade() analysis.getMedianGrade()
); );
if ( ! onlyNumbers) { if ( ! onlyNumbers) {
score += "_"; score += "_";
} }
score += String.format( score += String.format(
"%0"+digitsForGroup+"d", "%0"+digitsForGroup+"d",
amountOfJudges + analysis.getSecondMedianGroupSize() * analysis.getSecondMedianGroupSign() // amountOfJudges + secondMedianGroupSize * secondMedianGroupSign
amountOfJudges.add(
analysis.getSecondMedianGroupSize().multiply(
BigInteger.valueOf(analysis.getSecondMedianGroupSign())
)
)
); );
currentTally.moveJudgments(analysis.getMedianGrade(), analysis.getSecondMedianGrade()); currentTally.moveJudgments(analysis.getMedianGrade(), analysis.getSecondMedianGrade());

@ -5,30 +5,39 @@ import java.util.Arrays;
public class ProposalTally implements ProposalTallyInterface { public class ProposalTally implements ProposalTallyInterface {
protected Long[] tally; protected BigInteger[] tally;
// Should we allow this as well? // Should we allow this as well?
//public ProposalTally() {} //public ProposalTally() {}
public ProposalTally(Integer[] tally) { public ProposalTally(Integer[] tally) {
int tallyLength = tally.length; int tallyLength = tally.length;
Long[] doublesTally = new Long[tallyLength]; BigInteger[] bigTally = new BigInteger[tallyLength];
for (int i = 0 ; i < tallyLength ; i++) { for (int i = 0 ; i < tallyLength ; i++) {
doublesTally[i] = Long.valueOf(tally[i]); bigTally[i] = BigInteger.valueOf(tally[i]);
} }
setTally(doublesTally); setTally(bigTally);
} }
public ProposalTally(Long[] tally) { public ProposalTally(Long[] tally) {
int tallyLength = tally.length;
BigInteger[] bigTally = new BigInteger[tallyLength];
for (int i = 0 ; i < tallyLength ; i++) {
bigTally[i] = BigInteger.valueOf(tally[i]);
}
setTally(bigTally);
}
public ProposalTally(BigInteger[] tally) {
setTally(tally); setTally(tally);
} }
public void setTally(Long[] tally) { public void setTally(BigInteger[] tally) {
this.tally = tally; this.tally = tally;
} }
@Override @Override
public Long[] getTally() { public BigInteger[] getTally() {
return this.tally; return this.tally;
} }
@ -39,16 +48,17 @@ public class ProposalTally implements ProposalTallyInterface {
@Override @Override
public void moveJudgments(Integer fromGrade, Integer intoGrade) { public void moveJudgments(Integer fromGrade, Integer intoGrade) {
this.tally[intoGrade] += this.tally[fromGrade]; // this.tally[intoGrade] += this.tally[fromGrade];
this.tally[fromGrade] = 0L; this.tally[intoGrade] = this.tally[intoGrade].add(this.tally[fromGrade]);
this.tally[fromGrade] = BigInteger.ZERO;
} }
@Override @Override
public BigInteger getAmountOfJudgments() { public BigInteger getAmountOfJudgments() {
BigInteger sum = BigInteger.valueOf(0); BigInteger sum = BigInteger.ZERO;
int tallyLength = this.tally.length; int tallyLength = this.tally.length;
for (int i = 0 ; i < tallyLength ; i++) { for (int i = 0 ; i < tallyLength ; i++) {
sum = sum.add(BigInteger.valueOf(this.tally[i])); sum = sum.add(this.tally[i]);
} }
return sum; return sum;
} }

@ -1,35 +1,42 @@
package fr.mieuxvoter.mj; package fr.mieuxvoter.mj;
import java.math.BigInteger;
/** /**
* Collect useful data on a proposal tally. * Collect useful data on a proposal tally.
* Does NOT compute the rank, but provides all we need * Does NOT compute the rank, but provides all we need.
*
* This uses BigInteger because in a normalization scenario we use the
* smallest common multiple of the amounts of judges of proposals.
* It makes the code harder to read and understand, but it allows us
* to bypass the floating-point nightmare of the normalization of merit profiles,
* which is one way to handle default grades on some polls.
*/ */
public class ProposalTallyAnalysis { public class ProposalTallyAnalysis {
protected ProposalTallyInterface tally; protected ProposalTallyInterface tally;
protected Long totalSize = 0L; // amount of judges protected BigInteger totalSize = BigInteger.ZERO; // amount of judges
protected Integer medianGrade = 0; protected Integer medianGrade = 0;
protected Long medianGroupSize = 0L; // amount of judges in the median group protected BigInteger medianGroupSize = BigInteger.ZERO; // amount of judges in the median group
protected Integer contestationGrade = 0; // "best" grade of the contestation group protected Integer contestationGrade = 0; // "best" grade of the contestation group
protected Long contestationGroupSize = 0L; // of lower grades than median protected BigInteger contestationGroupSize = BigInteger.ZERO; // of lower grades than median
protected Integer adhesionGrade = 0; // "worst" grade of the adhesion group protected Integer adhesionGrade = 0; // "worst" grade of the adhesion group
protected Long adhesionGroupSize = 0L; // of higher grades than median protected BigInteger adhesionGroupSize = BigInteger.ZERO; // of higher grades than median
protected Integer secondMedianGrade = 0; // grade of the biggest group out of the median protected Integer secondMedianGrade = 0; // grade of the biggest group out of the median
protected Long secondMedianGroupSize = 0L; // either contestation or adhesion protected BigInteger secondMedianGroupSize = BigInteger.ZERO; // either contestation or adhesion
protected Integer secondMedianGroupSign = 0; // -1 for contestation, +1 for adhesion, 0 for empty group size protected Integer secondMedianGroupSign = 0; // -1 for contestation, +1 for adhesion, 0 for empty group size
public ProposalTallyAnalysis() {} public ProposalTallyAnalysis() {}
public ProposalTallyAnalysis(ProposalTallyInterface tally) { public ProposalTallyAnalysis(ProposalTallyInterface tally) {
@ -42,56 +49,58 @@ public class ProposalTallyAnalysis {
public void reanalyze(ProposalTallyInterface tally, Boolean favorContestation) { public void reanalyze(ProposalTallyInterface tally, Boolean favorContestation) {
this.tally = tally; this.tally = tally;
this.totalSize = 0L; this.totalSize = BigInteger.ZERO;
this.medianGrade = 0; this.medianGrade = 0;
this.medianGroupSize = 0L; this.medianGroupSize = BigInteger.ZERO;
this.contestationGrade = 0; this.contestationGrade = 0;
this.contestationGroupSize = 0L; this.contestationGroupSize = BigInteger.ZERO;
this.adhesionGrade = 0; this.adhesionGrade = 0;
this.adhesionGroupSize = 0L; this.adhesionGroupSize = BigInteger.ZERO;
this.secondMedianGrade = 0; this.secondMedianGrade = 0;
this.secondMedianGroupSize = 0L; this.secondMedianGroupSize = BigInteger.ZERO;
this.secondMedianGroupSign = 0; this.secondMedianGroupSign = 0;
Long[] gradesTallies = this.tally.getTally(); BigInteger[] gradesTallies = this.tally.getTally();
int amountOfGrades = gradesTallies.length; int amountOfGrades = gradesTallies.length;
for (int grade = 0; grade < amountOfGrades; grade++) { for (int grade = 0; grade < amountOfGrades; grade++) {
Long gradeTally = gradesTallies[grade]; BigInteger gradeTally = gradesTallies[grade];
assert(0 <= gradeTally); // Negative tallies are not allowed. //assert(0 <= gradeTally); // Negative tallies are not allowed.
this.totalSize += gradeTally; this.totalSize = this.totalSize.add(gradeTally);
} }
Integer medianOffset = 1; Integer medianOffset = 1;
if ( ! favorContestation) { if ( ! favorContestation) {
medianOffset = 2; medianOffset = 2;
} }
Long medianCursor = (long) Math.floor((this.totalSize + medianOffset) / 2.0); BigInteger medianCursor = this.totalSize.add(BigInteger.valueOf(medianOffset)).divide(BigInteger.TWO);
// Long medianCursor = (long) Math.floor((this.totalSize + medianOffset) / 2.0);
Long tallyBeforeCursor = 0L; BigInteger tallyBeforeCursor = BigInteger.ZERO;
Long tallyCursor = 0L; BigInteger tallyCursor = BigInteger.ZERO;
Boolean foundMedian = false; Boolean foundMedian = false;
Integer contestationGrade = 0; Integer contestationGrade = 0;
Integer adhesionGrade = 0; Integer adhesionGrade = 0;
for (int grade = 0; grade < amountOfGrades; grade++) { for (int grade = 0; grade < amountOfGrades; grade++) {
Long gradeTally = gradesTallies[grade]; BigInteger gradeTally = gradesTallies[grade];
tallyBeforeCursor = tallyCursor; tallyBeforeCursor = tallyCursor;
tallyCursor += gradeTally; tallyCursor = tallyCursor.add(gradeTally);
if ( ! foundMedian) { if ( ! foundMedian) {
if (tallyCursor >= medianCursor) { if (-1 < tallyCursor.compareTo(medianCursor)) { // tallyCursor >= medianCursor
foundMedian = true; foundMedian = true;
this.medianGrade = grade; this.medianGrade = grade;
this.contestationGroupSize = tallyBeforeCursor; this.contestationGroupSize = tallyBeforeCursor;
this.medianGroupSize = gradeTally; this.medianGroupSize = gradeTally;
this.adhesionGroupSize = this.totalSize - this.contestationGroupSize - this.medianGroupSize; // this.adhesionGroupSize = this.totalSize - this.contestationGroupSize - this.medianGroupSize;
this.adhesionGroupSize = this.totalSize.subtract(this.contestationGroupSize).subtract(this.medianGroupSize);
} else { } else {
if (0 < gradeTally) { if (1 == gradeTally.compareTo(BigInteger.ZERO)) { // 0 < gradeTally
contestationGrade = grade; contestationGrade = grade;
} }
} }
} else { } else {
if (0 < gradeTally && 0 == adhesionGrade) { if (1 == gradeTally.compareTo(BigInteger.ZERO) && 0 == adhesionGrade) {
adhesionGrade = grade; adhesionGrade = grade;
} }
} }
@ -99,12 +108,15 @@ public class ProposalTallyAnalysis {
this.contestationGrade = contestationGrade; this.contestationGrade = contestationGrade;
this.adhesionGrade = adhesionGrade; this.adhesionGrade = adhesionGrade;
this.secondMedianGroupSize = Math.max(this.contestationGroupSize, this.adhesionGroupSize); // this.secondMedianGroupSize = Math.max(this.contestationGroupSize, this.adhesionGroupSize);
this.secondMedianGroupSize = this.contestationGroupSize.max(this.adhesionGroupSize);
this.secondMedianGroupSign = 0; this.secondMedianGroupSign = 0;
if (this.contestationGroupSize < this.adhesionGroupSize) { // if (this.contestationGroupSize < this.adhesionGroupSize) {
if (1 == this.adhesionGroupSize.compareTo(this.contestationGroupSize)) {
this.secondMedianGrade = this.adhesionGrade; this.secondMedianGrade = this.adhesionGrade;
this.secondMedianGroupSign = 1; this.secondMedianGroupSign = 1;
} else if (this.contestationGroupSize > this.adhesionGroupSize) { // } else if (this.contestationGroupSize > this.adhesionGroupSize) {
} else if (1 == this.contestationGroupSize.compareTo(this.adhesionGroupSize)) {
this.secondMedianGrade = this.contestationGrade; this.secondMedianGrade = this.contestationGrade;
this.secondMedianGroupSign = -1; this.secondMedianGroupSign = -1;
} else { } else {
@ -116,16 +128,16 @@ public class ProposalTallyAnalysis {
this.secondMedianGroupSign = 1; this.secondMedianGroupSign = 1;
} }
} }
if (0 == this.secondMedianGroupSize) { if (0 == this.secondMedianGroupSize.compareTo(BigInteger.ZERO)) {
this.secondMedianGroupSign = 0; this.secondMedianGroupSign = 0;
} }
} }
public Long getTotalSize() { public BigInteger getTotalSize() {
return totalSize; return totalSize;
} }
public void setTotalSize(Long totalSize) { public void setTotalSize(BigInteger totalSize) {
this.totalSize = totalSize; this.totalSize = totalSize;
} }
@ -136,12 +148,12 @@ public class ProposalTallyAnalysis {
public void setMedianGrade(Integer medianGrade) { public void setMedianGrade(Integer medianGrade) {
this.medianGrade = medianGrade; this.medianGrade = medianGrade;
} }
public Long getMedianGroupSize() { public BigInteger getMedianGroupSize() {
return medianGroupSize; return medianGroupSize;
} }
public void setMedianGroupSize(Long medianGroupSize) { public void setMedianGroupSize(BigInteger medianGroupSize) {
this.medianGroupSize = medianGroupSize; this.medianGroupSize = medianGroupSize;
} }
@ -153,11 +165,11 @@ public class ProposalTallyAnalysis {
this.contestationGrade = contestationGrade; this.contestationGrade = contestationGrade;
} }
public Long getContestationGroupSize() { public BigInteger getContestationGroupSize() {
return contestationGroupSize; return contestationGroupSize;
} }
public void setContestationGroupSize(Long contestationGroupSize) { public void setContestationGroupSize(BigInteger contestationGroupSize) {
this.contestationGroupSize = contestationGroupSize; this.contestationGroupSize = contestationGroupSize;
} }
@ -168,15 +180,15 @@ public class ProposalTallyAnalysis {
public void setAdhesionGrade(Integer adhesionGrade) { public void setAdhesionGrade(Integer adhesionGrade) {
this.adhesionGrade = adhesionGrade; this.adhesionGrade = adhesionGrade;
} }
public Long getAdhesionGroupSize() { public BigInteger getAdhesionGroupSize() {
return adhesionGroupSize; return adhesionGroupSize;
} }
public void setAdhesionGroupSize(Long adhesionGroupSize) { public void setAdhesionGroupSize(BigInteger adhesionGroupSize) {
this.adhesionGroupSize = adhesionGroupSize; this.adhesionGroupSize = adhesionGroupSize;
} }
public Integer getSecondMedianGrade() { public Integer getSecondMedianGrade() {
return secondMedianGrade; return secondMedianGrade;
} }
@ -185,11 +197,11 @@ public class ProposalTallyAnalysis {
this.secondMedianGrade = secondMedianGrade; this.secondMedianGrade = secondMedianGrade;
} }
public Long getSecondMedianGroupSize() { public BigInteger getSecondMedianGroupSize() {
return secondMedianGroupSize; return secondMedianGroupSize;
} }
public void setSecondMedianGroupSize(Long secondMedianGroupSize) { public void setSecondMedianGroupSize(BigInteger secondMedianGroupSize) {
this.secondMedianGroupSize = secondMedianGroupSize; this.secondMedianGroupSize = secondMedianGroupSize;
} }

@ -9,7 +9,7 @@ public interface ProposalTallyInterface {
* the amount of judgments received for each Grade by the Proposal, * the amount of judgments received for each Grade by the Proposal,
* from "worst" ("most conservative") Grade to "best" Grade. * from "worst" ("most conservative") Grade to "best" Grade.
*/ */
public Long[] getTally(); public BigInteger[] getTally();
/** /**
* Should be the sum of getTally() * Should be the sum of getTally()

@ -1,19 +1,26 @@
package fr.mieuxvoter.mj; package fr.mieuxvoter.mj;
import java.math.BigInteger;
public class Tally implements TallyInterface { public class Tally implements TallyInterface {
protected ProposalTallyInterface[] proposalsTallies; protected ProposalTallyInterface[] proposalsTallies;
protected Long amountOfJudges = 0L; protected BigInteger amountOfJudges = BigInteger.ZERO;
public Tally(ProposalTallyInterface[] proposalsTallies, BigInteger amountOfJudges) {
setProposalsTallies(proposalsTallies);
setAmountOfJudges(amountOfJudges);
}
public Tally(ProposalTallyInterface[] proposalsTallies, Long amountOfJudges) { public Tally(ProposalTallyInterface[] proposalsTallies, Long amountOfJudges) {
setProposalsTallies(proposalsTallies); setProposalsTallies(proposalsTallies);
setAmountOfJudges(amountOfJudges); setAmountOfJudges(BigInteger.valueOf(amountOfJudges));
} }
public Tally(ProposalTallyInterface[] proposalsTallies, Integer amountOfJudges) { public Tally(ProposalTallyInterface[] proposalsTallies, Integer amountOfJudges) {
setProposalsTallies(proposalsTallies); setProposalsTallies(proposalsTallies);
setAmountOfJudges(Long.valueOf(amountOfJudges)); setAmountOfJudges(BigInteger.valueOf(amountOfJudges));
} }
public ProposalTallyInterface[] getProposalsTallies() { public ProposalTallyInterface[] getProposalsTallies() {
@ -28,11 +35,11 @@ public class Tally implements TallyInterface {
return proposalsTallies.length; return proposalsTallies.length;
} }
public Long getAmountOfJudges() { public BigInteger getAmountOfJudges() {
return amountOfJudges; return amountOfJudges;
} }
public void setAmountOfJudges(Long amountOfJudges) { public void setAmountOfJudges(BigInteger amountOfJudges) {
this.amountOfJudges = amountOfJudges; this.amountOfJudges = amountOfJudges;
} }

@ -1,11 +1,13 @@
package fr.mieuxvoter.mj; package fr.mieuxvoter.mj;
import java.math.BigInteger;
public interface TallyInterface { public interface TallyInterface {
public ProposalTallyInterface[] getProposalsTallies(); public ProposalTallyInterface[] getProposalsTallies();
public Long getAmountOfJudges(); public BigInteger getAmountOfJudges();
public Integer getAmountOfProposals(); public Integer getAmountOfProposals();
} }

@ -6,7 +6,7 @@ public class TallyWithDefaultGrade extends Tally implements TallyInterface {
protected Integer defaultGrade = 0; protected Integer defaultGrade = 0;
public TallyWithDefaultGrade(ProposalTallyInterface[] proposalsTallies, Integer amountOfJudges, Integer defaultGrade) { public TallyWithDefaultGrade(ProposalTallyInterface[] proposalsTallies, BigInteger amountOfJudges, Integer defaultGrade) {
super(proposalsTallies, amountOfJudges); super(proposalsTallies, amountOfJudges);
this.defaultGrade = defaultGrade; this.defaultGrade = defaultGrade;
fillWithDefaultGrade(); fillWithDefaultGrade();
@ -18,16 +18,22 @@ public class TallyWithDefaultGrade extends Tally implements TallyInterface {
fillWithDefaultGrade(); fillWithDefaultGrade();
} }
public TallyWithDefaultGrade(ProposalTallyInterface[] proposalsTallies, Integer amountOfJudges, Integer defaultGrade) {
super(proposalsTallies, amountOfJudges);
this.defaultGrade = defaultGrade;
fillWithDefaultGrade();
}
protected void fillWithDefaultGrade() { protected void fillWithDefaultGrade() {
int amountOfProposals = getAmountOfProposals(); int amountOfProposals = getAmountOfProposals();
for (int i = 0 ; i < amountOfProposals ; i++) { for (int i = 0 ; i < amountOfProposals ; i++) {
ProposalTallyInterface proposal = getProposalsTallies()[i]; ProposalTallyInterface proposal = getProposalsTallies()[i];
BigInteger amountOfJudgments = proposal.getAmountOfJudgments(); BigInteger amountOfJudgments = proposal.getAmountOfJudgments();
BigInteger missingAmount = BigInteger.valueOf(this.amountOfJudges).subtract(amountOfJudgments); BigInteger missingAmount = this.amountOfJudges.subtract(amountOfJudgments);
int missingSign = missingAmount.compareTo(BigInteger.ZERO); int missingSign = missingAmount.compareTo(BigInteger.ZERO);
assert(0 <= missingSign); // More judgments than judges! assert(0 <= missingSign); // ERROR: More judgments than judges!
if (0 < missingSign) { if (0 < missingSign) {
proposal.getTally()[this.defaultGrade] = proposal.getTally()[this.defaultGrade] + missingAmount.longValue(); proposal.getTally()[this.defaultGrade] = proposal.getTally()[this.defaultGrade].add(missingAmount);
} }
} }
} }

Loading…
Cancel
Save