dimesum

Home / Blog / Techniek

Techniek

Afronding bij splitsen: de cent tussen app en rekenblad

· 12 min leestijd ·

Een rekening van $100,00 in drieën gedeeld laat één cent over die een spreadsheet laat vallen en Dimesum aan één persoon geeft, gekozen door een vaste hash van de rekening. Hier staan de uitgewerkte tabel, de regel die we vervingen en de twee valutafouten die alleen een rekenblad kan maken.

Je spreadsheet zegt $66,66 en de app zegt $66,67. Die ene cent is afronding bij het splitsen van een rekening, en het is het meest voorkomende bericht dat we krijgen van iemand die Dimesum met Excel heeft vergeleken. Het korte antwoord: het rekenblad rondt elk aandeel apart af en verliest de overgebleven cent, terwijl Dimesum die cent aan één persoon geeft, gekozen door een vaste hash van de rekening, zodat de aandelen altijd weer optellen tot het totaal.

Het probleem, de oorzaak en de oplossing, in drie zinnen die je kunt overnemen. Een rekening van $100,00 in drieën gedeeld kan niet in drie gelijke bedragen worden betaald, dus iemand draagt $33,34. Een spreadsheet die elke cel afrondt, toont drie keer $33,33 en laat stilletjes een cent vallen, terwijl Dimesum de cent houdt en met de eigen hash van de rekening beslist wie hem draagt. De twee zijn het eens over elke rekening die gelijk deelbaar is en verschillen hooguit één cent per persoon over elke rekening die dat niet is.

Het symptoom: een cent die de ene kant heeft en de andere niet

De melding komt meestal op dezelfde manier binnen. Iemand exporteert een maand aan rekeningen, bouwt de saldi opnieuw op in een rekenblad, en vindt een paar cent verschil. Aan geen van beide kanten ontbreekt meer dan een cent per rekening, en toch krijgt niemand de twee gelijk.

We schreven over de vier redenen waarom een groepssaldo fout lijkt in waarom gedeelde saldi nooit kloppen. Dit stuk neemt de eerste daarvan, de afgeronde cent, en volgt die tot in een spreadsheet, omdat dat de plek is waar een zorgvuldig iemand ons gaat controleren. Het behandelt ook de twee plekken waar een rekenblad misgaat en een app niet kan: twee valuta in één kolom optellen, en de yen twee decimalen geven die hij niet heeft.

Een rekening van $100,00, in drieën, in een rekenblad en in de app

Emma betaalt $100,00 voor het diner. Lucas, Sofia en Emma splitsen het gelijk. Honderd dollar gedeeld door drie is $33,333 en zo eindeloos door, en dat kan geen kaart betalen.

Een rekenblad kan dat eindeloze getal vasthouden. Typ =100/3 in drie cellen, maak ze op met twee decimalen, en elke cel toont $33,33. De SUM-cel toont $100,00, omdat die de verborgen cijfers optelt en niet die op het scherm. Telt een lezer de drie zichtbare cellen nu met een rekenmachine op, dan komt die op $99,99.

Het zorgvuldige rekenblad rondt in plaats daarvan af: =ROUND(100/3, 2) in elke cel. Nu bevat elke cel echt $33,33, is de SUM echt $99,99, en heeft de cent het rekenblad verlaten. Emma krijgt $33,33 van Lucas en $33,33 van Sofia, dus het rekenblad zegt dat ze $66,66 terugkrijgt. Haar eigen aandeel hoorde $33,33 te zijn, maar ze heeft $33,34 van het diner betaald zonder dat iemand het opschreef.

Eén diner van $100,00, betaald door Emma, in drieën gedeeld: twee spreadsheets en twee rekeningen in Dimesum
Waar het werd gesplitstAandeel EmmaAandeel LucasAandeel SofiaAandelen tellen op totEmma krijgt
Dimesum, een rekening waarvan de hash Emma de oneven cent geeft$33,34$33,33$33,33$100,00$66,66
Dimesum, een rekening waarvan de hash Lucas de oneven cent geeft$33,33$33,34$33,33$100,00$66,67
Rekenblad, =100/3 getoond met twee decimalen$33,33$33,33$33,33$100,00 in SUM, $99,99 op het scherm$66,67 op het scherm
Rekenblad, =ROUND(100/3, 2)$33,33$33,33$33,33$99,99$66,66

Elke rij is rekenwerk dat je zelf kunt overdoen.

In de tweede rij van Dimesum is Lucas $33,34 verschuldigd en Sofia $33,33, en $33,34 plus $33,33 is $66,67. In het afgeronde rekenblad is $33,33 plus $33,33 $66,66. Geen van beide is een fout. Het zijn twee verschillende regels over één cent, en maar één ervan houdt de cent op de administratie.

Waarom elk aandeel eerst naar beneden wordt afgerond

Dimesum splitst met de methode van de grootste overschotten, een regel die sommige parlementen gebruiken om stemaandelen om te zetten in hele zetels. Elk bedrag wordt opgeslagen als een heel getal in de kleinste eenheid van de valuta, dus $100,00 is 10.000 cent. Ieders exacte aandeel wordt als breuk berekend, en daarna krijgt iedereen de hele centen eronder: 3.333 per persoon, samen 9.999.

Dan blijft er één cent over. De overgebleven centen worden één voor één uitgedeeld, aan de mensen van wie de breuk het meest werd afgekapt. Bij een gelijke verdeling is ieders breuk even groot, een derde cent, dus de regel heeft een beslisser nodig bij gelijkspel. Die beslisser is waar onze eerste versie misging.

De garantie die de methode geeft, is degene die een rekenblad niet kan geven: de aandelen tellen precies weer op tot het totaal, en geen aandeel ligt meer dan één cent van zijn exacte waarde af. Hetzelfde rekenwerk draait voor een gelijke verdeling, een verdeling in percentages, gewogen aandelen, elke regel van een rekening per item en elke pot voor btw of fooi erop. Ons stuk over apps om een rekening per item te splitsen laat het zien bij een diner voor vier met een korting.

Wat we eerst probeerden: het oudste lid nam elke oneven cent

De eerste beslisser bij gelijkspel was de voor de hand liggende. Leden staan gesorteerd op wanneer ze lid werden, dus gelijkspel ging naar het oudste lid. Het is deterministisch, het is makkelijk te testen, en bij geen enkele losse rekening kon iemand het oneerlijk noemen.

Over een jaar is het een toeslag. Een huis met drie mensen splitst huur, stroom, internet en boodschappen, en veel van die rekeningen laten een cent over. Elke van die centen ging naar dezelfde persoon, degene die de groep opzette. Een cent is niets; een paar honderd ervan in één richting is een patroon dat iemand uiteindelijk opmerkt in een rekenblad.

Het antwoord van de oprichter op 21 augustus 2026 was dat een willekeurige deelnemer hem moest dragen, zodat het over veel rekeningen uitmiddelt. Willekeur had voor ons een addertje. Dimesum herberekent de verdeling van een rekening telkens als die wordt bewerkt, en een bewerking wordt vastgelegd als een nieuwe boeking die de verdeling opnieuw vastlegt, zoals beschreven in waarom een bewerking haar verdeling opnieuw moet vastleggen. Met een echte willekeurige trekking zou een bewerking die alleen de naam van de rekening veranderde, opnieuw loten, de cent naar iemand anders verplaatsen en een correctie boeken voor geld dat nooit bewoog.

De oplossing: laat de oneven cent rouleren via een vaste hash van de rekening

Dus werd willekeurig pseudowillekeurig en vast. Elke rekening heeft haar eigen id, en die hashen we met FNV-1a, een kleine hash die op elke machine en in elke build hetzelfde antwoord geeft. De hash kiest waar in de geordende lijst het uitdelen van de overgebleven centen begint. Dezelfde rekening, hetzelfde antwoord, elke keer dat ze wordt berekend; over veel rekeningen komt het beginpunt ongeveer even vaak bij ieder terecht.

De geordende lijst is nog steeds de volgorde van de grootste overschotten, met gelijkspel beslist in het voordeel van het oudste lid. De hash verschuift alleen waar het uitdelen begint. Bij een gelijke verdeling in drieën betekent dat dat elke rekening een van de drie mensen kiest om $33,34 te dragen, en die keuze verandert voor die rekening nooit.

Daarom verschillen je rekenblad en de app per rekening op een andere manier. Bij het ene diner van $100,00 geeft de hash Emma de cent en zijn de twee het erover eens dat ze $66,66 krijgt. Bij het volgende geeft hij Lucas de cent en zegt de app $66,67. Een rekenblad met één regel voor elke rij kan dat niet nabootsen, tenzij het de hash overneemt.

De prijs die we accepteerden

Twee rekeningen met dezelfde inhoud kunnen nu één cent verschillen. Twee diners van $100,00 met dezelfde drie mensen kunnen bij het ene $33,34 voor Emma opleveren en bij het andere $33,34 voor Sofia. Twee van onze eigen end-to-endtests vergeleken de aandelen van de ene rekening met die van een andere en braken op de dag dat dit live ging; ze controleren nu de uitkomst van de regel.

We denken dat dat de juiste ruil is. Het grootboek onder elk saldo voegt alleen toe, dus een cent die zonder reden verschuift, zou voor altijd worden opgeschreven; het ontwerp staat in het grootboek dat alleen toevoegt, achter elke verdeling. Een cent die per rekening vastligt en over mensen wordt gespreid, heeft nooit een correctie nodig.

Een kolom die dollars bij euro's optelt is geen totaal

Het tweede verschil is groter dan een cent en het ligt altijd aan het rekenblad. Op een reis betaalt Emma een hotelnacht van €90 en een museumkaartje van $60, en het rekenblad heeft één kolom Bedrag met een SUM onderaan. Die zegt 150. Dat getal heeft geen valuta, dus niemand kan het verschuldigd zijn.

Dimesum houdt elk saldo per valuta bij en telt nooit over valuta heen op. De groep ziet wat er in euro verschuldigd is en, apart, wat er in dollar verschuldigd is. Spreekt de groep een koers af, dan kan Dimesum de saldi samengevoegd in één valuta tonen, met de koers erbij vermeld, en de schuld zelf blijft in de valuta waarin ze werd uitgegeven.

De fouten die ontstaan als je het anders doet, staan in de geldfouten die een tweede valuta veroorzaakt. Is een reis de reden dat je vergelijkt, dan zet apps om uitgaven in meerdere valuta te splitten op een rij hoe andere apps een tweede valuta bijhouden.

Samenvoegen brengt een eigen afronding mee. Een omrekening rondt af op hele centen, bij een half weg van nul, dus saldi die in yen op nul uitkwamen, kunnen in dollar op één cent te veel uitkomen. We laten het lid met het laagste id tot één kleinste eenheid per omrekening opvangen, en daarboven wordt het afrekenplan geweigerd. Een plan dat stilletjes $1 fout zit, is erger dan een foutmelding, omdat iemand het zou betalen.

De yen heeft geen centen, en een rekenblad geeft hem er toch twee

Het derde verschil duikt op bij elke reis naar Japan. De yen heeft geen kleinere eenheid: de exponent in de valutanorm ISO 4217 is nul, dus ¥1 is het kleinste bedrag dat iemand kan betalen. Een diner van ¥10.000 in drieën gedeeld komt in Dimesum uit op ¥3.334, ¥3.333 en ¥3.333, wat optelt tot ¥10.000.

Een rekenblad dat voor geld is opgemaakt, toont drie keer ¥3.333,33, een bedrag dat geen munt betaalt. Rond het af op hele yen en het toont drie keer ¥3.333, wat optelt tot ¥9.999. De yen verliest één eenheid op dezelfde manier als de dollar een cent verloor.

We hebben dit zelf stukgemaakt voordat we het repareerden.

De code die een bedrag uit een regel tekst leest, zette dat ooit om in kleinste eenheden door met 100 te vermenigvuldigen, wat klopt voor dollars en euro's en fout is voor yen: een taxi van ¥2.000 werd ¥200.000. Dat was een fout van een factor 100, en geen afrondingsregel had die kunnen opvangen.

De omrekening leest nu de exponent van elke valuta uit de ISO-tabel, en een bedrag dat fijner is dan de kleinste eenheid van een valuta wordt geweigerd in plaats van afgerond. Bedragen uit tekst lezen heeft bij ons een langere geschiedenis, verteld in waarom we onze uitgavenparser verwijderden. Hoe een reis in yen zonder dat gedoe wordt gesplitst, staat in apps om rekeningen te splitten in Japan.

Wat een spreadsheet nog meer met geld doet

Excel slaat getallen op als binaire drijvende komma, en sommige decimalen hebben geen exacte binaire vorm. De eigen notitie van Microsoft over rekenen met drijvende komma in Excel legt uit waarom een som een haartje kan afwijken van het bedrag dat je verwacht. Meestal verbergt de weergave het, en precies daarom kunnen de cel die je ziet en de waarde die je optelt verschillen.

De afrondingsfuncties hebben ook hun eigen regels. De functie ROUND van Excel (AFRONDEN in een Nederlandse Excel) en ROUND in Google Sheets ronden elke cel apart af, zonder iets te weten van de andere cellen in de verdeling. Dat is het hele verschil: een verdeling moet de aandelen samen afronden, zodat ze nog steeds optellen tot de rekening.

Dimesum slaat geld nooit op als fractie van een eenheid. Elk bedrag is een heel aantal centen, of yen, met de valuta ernaast geschreven, en elke verdeling behoudt haar totaal precies. Houd je het geld van de groep toch liever in een rekenblad bij, dan is ons sjabloon om gedeelde uitgaven bij te houden een redelijk begin, en behandelt spreadsheet of app voor gedeelde uitgaven waar het rekenblad niet meer volstaat.

Zo laat je je rekenblad overeenkomen met de app

Je kunt de getallen van Dimesum met de hand nabootsen. Werk in hele centen. Geef ieder de hele centen onder het exacte aandeel, tel de overgebleven centen, en deel ze één voor één uit.

  1. Zet de rekening om in centen: $100,00 is 10.000.
  2. Geef ieder het naar beneden afgeronde exacte aandeel: 3.333 per persoon, samen 9.999.
  3. Geef de overgebleven cent aan de persoon die de app hem laat dragen, en controleer of de aandelen optellen tot 10.000.
  4. Houd één rekenblad per valuta bij, en zet nooit een SUM over twee ervan heen.

Stap drie is de enige die je zonder de hash van de rekening niet kunt voorspellen, dus lees die van de rekening af. Het langere rekenwerk voor elke verdeling, met gewichten en percentages, staat in de rekenmethode om uitgaven te splitsen, en dezelfde controle toegepast op de hele geschiedenis van een groep staat in zo houd je bij wie wie wat schuldig is op een reis.

Wat dit nog steeds niet kan

Het kan je rekenblad en de app niet zonder moeite op elke rekening laten overeenkomen. Een rekenblad met één afrondingsregel per kolom verschilt van Dimesum met een cent bij ruwweg elke rekening die een rest overlaat, en de persoon die de cent draagt, wisselt van rekening tot rekening. Dat is de regel die werkt.

Het kan een samengevoegd totaal ook niet exact maken. Een saldo dat in één valuta wordt getoond tegen een afgesproken koers is een indicatie, en het afrekenplan dat daarop is gebouwd, kan per omrekening één kleinste eenheid afwijken. De schuld die telt, blijft in de valuta waarin ze werd uitgegeven, en daarom gebeurt een groep afrekenen één valuta tegelijk.

Controleer de som, niet elke cel

Verschillen de app en je rekenblad een cent, tel dan de aandelen op de rekening op: zijn ze gelijk aan het totaal, dan ligt de cent met opzet bij één persoon. Om te zien bij wie, open Dimesum, tik op de rekening, en lees het aandeel dat één cent groter is dan de rest.

Veelgestelde vragen

Waarom verschilt mijn app om rekeningen te splitten een cent van Excel?

Omdat Excel elk aandeel apart afrondt en de app de aandelen samen afrondt. Een rekening van $100,00 in drieën gedeeld is in een afgerond rekenblad drie keer $33,33, wat optelt tot $99,99. Dimesum geeft één persoon $33,34 zodat de aandelen optellen tot $100,00, en een vaste hash van de rekening beslist wie die cent draagt.

Wie betaalt de extra cent als een rekening in drieën wordt gedeeld?

Eén persoon, en in Dimesum beslist de eigen hash van de rekening welke. De aandelen worden berekend met de methode van de grootste overschotten, en de plek waar het uitdelen van de overgebleven centen begint, rouleert via een vaste hash van de rekening. Dezelfde rekening geeft altijd hetzelfde antwoord, en over veel rekeningen komt de cent ongeveer even vaak bij ieder terecht.

Waarom kiest Dimesum geen willekeurige persoon voor de oneven cent?

Omdat een echte willekeurige trekking de cent zou verplaatsen elke keer dat een rekening wordt bewerkt. Dimesum legt bij elke bewerking de verdeling opnieuw vast, dus een nieuwe trekking zou een correctie boeken voor geld dat nooit bewoog. Een vaste hash van de rekening gedraagt zich over veel rekeningen als een willekeurige keuze en geeft voor één rekening elke keer hetzelfde antwoord.

Kan ik saldi in twee valuta in één kolom van een spreadsheet optellen?

Nee, het totaal betekent niets. €90 en $60 opgeteld tot 150 is een getal zonder valuta, dus niemand kan het verschuldigd zijn. Dimesum houdt een saldo per valuta bij en telt nooit over valuta heen op; een groep kan ze samengevoegd zien tegen een koers die ze afspreekt, met die koers erbij vermeld, terwijl elke schuld in de valuta blijft waarin ze werd uitgegeven.

Hoe splitst Dimesum yen als er geen centen zijn?

In hele yen, omdat de kleinste eenheid van de yen ¥1 is. Een diner van ¥10.000 in drieën gedeeld is ¥3.334, ¥3.333 en ¥3.333, wat optelt tot ¥10.000. Een rekenblad dat met twee decimalen is opgemaakt, toont ¥3.333,33, wat geen munt kan betalen, en elke cel afronden op hele yen verliest ¥1 op dezelfde manier als een rekenblad in dollars een cent verliest.