## Pounds, Shillings, Pence

### April 7, 2015

Mixed-radix number systems have a base, or radix, that varies at each position. For instance, the old-style British pounds, shillings and pence form a mixed-radix system where there are twelve pence in a shilling and twenty shillings in a pound, and calendars form a mixed-radix system where there are sixty seconds in a minute, sixty minutes in an hour, twenty-four hours in a day, and seven days in a week.

Your task is to write a program that accepts a definition of a mixed-radix system — for instance, (7 24 60 60) for the calendar mentioned above — and performs addition and subtraction of numbers written in that system. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 9 Responses to “Pounds, Shillings, Pence”

1. Rutger said

In Python.

```
for i in range(len(radices)-1, -1, -1):
return result

result = 0
return result

if __name__ == "__main__":
# weeks, days, hours, minutes, seconds

# 1 second less than 1 week
number = 7*24*60*60-1

# 1 second less than 1 hour

# 1000 pounds, 20 shilling, 12 pence
maximum = 1
maximum *= v
# some random tests
import random
for i in range(10000):
number = random.randint(1, maximum)
```
2. Rutger said

fix markup?

```def number_to_mixed_radix(number, radices):
for i in range(len(radices)-1, -1, -1):
return result

result = 0
return result

if __name__ == "__main__":
# weeks, days, hours, minutes, seconds

# 1 second less than 1 week
number = 7*24*60*60-1

# 1 second less than 1 hour

# 1000 pounds, 20 shilling, 12 pence
maximum = 1
maximum *= v
# some random tests
import random
for i in range(10000):
number = random.randint(1, maximum)
```
3. Rutger said

really

```def number_to_mixed_radix(number, radices):
for i in range(len(radices)-1, -1, -1):
return result

result = 0
return result

if __name__ == "__main__":
# weeks, days, hours, minutes, seconds

# 1 second less than 1 week
number = 7*24*60*60-1

# 1 second less than 1 hour

# 1000 pounds, 20 shilling, 12 pence
maximum = 1
maximum *= v
# some random tests
import random
for i in range(10000):
number = random.randint(1, maximum)
```
4. matthew said

Nice little problem. Here’s a solution using C arrays, handling carries and borrows as in normal decimal addition. Input can be non-normalized, but the output is always normalized (so adding or subtracting zero normalizes a number). Least significant digit first (though I’ve printed the digits in the opposite order):

```#include <stdio.h>

int radixadd(int *a, const int *b, const int *r, int n) {
for (int c = 0, i = 0; ; i++) {
int k = a[i]+b[i]+c;
if (i < n) {
c = k/r[i]; a[i] = k%r[i];
} else {
a[n] = k; break;
}
}
}

int radixsub(int *a, const int *b, const int *r, int n) {
for (int c = 0, i = 0; ; i++) {
int k = a[i]-b[i]+c;
if (i < n) {
c = k/r[i]; a[i] = k%r[i];
if (a[i] < 0) {
a[i] += r[i]; c--; // modulus should be positive
}
} else {
a[n] = k; break;
}
}
}

int total(int *a, const int *r, int n) {
int c = a[n];
for (int i = n; i > 0; i--) {
c = r[i-1]*c + a[i-1];
}
return c;
}

int main()
{
int r[] = { 12, 20 };
int zero[] = { 0, 0, 0 };
int a[] = { 1729, 0, 0 };
int b[] = { 250, 0, 0 };
printf("%d %d %d: %d\n", a,a,a, total(a,r,2));
printf("%d %d %d: %d\n", b,b,b, total(b,r,2));
printf("%d %d %d: %d\n", a,a,a, total(a,r,2));
radixsub(a,b,r,2); // Sub b from a
radixsub(a,b,r,2); // Sub b from a
printf("%d %d %d: %d\n", a,a,a, total(a,r,2));
radixsub(b,a,r,2); // Sub a from b
printf("%d %d %d: %d\n", b,b,b, total(b,r,2));
printf("%d %d %d: %d\n", b,b,b, total(b,r,2));
}
```
5. matthew said

6. Krishnan R said

Solution in Java. However, leading zero’s are not removed..

```package com.experiment;

public class PoundsShillingsPence {

private static int[] result;
public static void main(String[] args) {
operate('+', new int[] {20, 12}, new int[] {8, 12, 10}, new int[] {7, 14, 3});
operate('-', new int[] {20, 12}, new int[] {8, 12, 10}, new int[] {7, 14, 3});
operate('-', new int[] {20, 12}, new int[] {7, 14, 3}, new int[] {8, 12, 10});
}

private static void normalize(int[] scheme, int[] input) {
int mod, s, i, carry=0;
result = new int[input.length];
for(s = scheme.length-1, i = input.length-1;i>=0;i--,s--) {
if(s>=0) {
mod = (input[i]+carry)%scheme[s];
carry = (input[i]+carry)/scheme[s];
if(mod<0) {
mod = mod+scheme[s];
carry = carry-1;
}
result[i] = mod;
} else {
result[i] = (input[i]+carry);
}
}
System.out.print("{");
for(int l=0;l<result.length;l++) {
System.out.print(result[l]);
if(l!=result.length-1)
System.out.print(",");
}
System.out.print("}\n");
}

private static void operate(char operator, int[] schema, int[] input1, int[] input2) {
int i1 = input1.length;
int i2 = input2.length;
int r = i1<i2?i2:i1;
int result[] = new int[r];

for(i1=i1-1,i2=i2-1,r=r-1;;i1--,i2--,r--) {
if(i1<0 && i2<0) {
break;
}
if(i1<0) {
result[i2] = input2[i2];
continue;
}
if(i2<0) {
result[i1] = input1[i1];
continue;
}
if(operator=='+') {
result[r] = input1[i1]+input2[i2];
}
else if(operator=='-')
result[r] = input1[i1]-input2[i2];
else {
System.out.println("Invalid operator. Only + and - are supported");
return;
}
}
normalize(schema, result);
}
}
```
7. Dennis Decker Jensen said

An example in ISO Prolog (gprolog):

:- initialization(main).

main :-
% Weeks, days, hours, minutes, seconds
Number is 7*24*60*60-1, % 1 second less than 1 week
format(‘~d weeks, ~d days, ~d hours, ~d minutes, and ~d seconds~n’, Ns),
Hourm1sec = [0,0,1,0,-1], % 1 second less than 1 hour
format(‘1 second less than 1 hour ~w = ~w = ~d seconds~n’,
[Hourm1sec,Nd,Secs]),
Ym1sec = [364,0,0,-1], % 1 year – 1 second, but 7*52 = 364
format(‘1 second less than 1 year in days and time: ~w~n’,[Ym1sec]),
format(‘1 second less than 1 year in weeks, days and time: ~w~n’,
[Yw]),
format(‘ 7 weekdays * 52 weeks in days: 364~n’,[]),
format(‘1 second less than 1 year in seconds: ~d~n’,[S]),
% Pounds, shillings, pence
format(‘~d £, ~d shillings, and ~d pence are ~d pence total~n’,
[8,12,10,Pence]),
format(‘~d pence are ~d £, ~d shillings, and ~d pence~n’,[Pence|Ps]),
% Degrees, minutes, seconds
format(’53 degrees 45”20”” W is ~d seconds west~n’,[Seconds]),
% Binary numbers
format(’67 in a binary (octet) is ~w~n’,[B]),
format(‘7F hexadecimal is ~d decimal~n’, [Hx]),
format(‘254 decimal is ~w hexadecimal~n’, [Hx1]),
halt.

mixed_radix_number(Rs, Ns, S) :- nonvar(Ns), !,
reverse(Rs, Rs1),

S1 is R * S0 + N,

Rem is S mod R,
S1 is floor(S / R),
[/source/

8. Dennis Decker Jensen said

Alas, try again to get formatting right:

```:- initialization(main).

main :-
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;% Weeks, days, hours, minutes, seconds
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number is 7*24*60*60-1, % 1 second less than 1 week
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('~d weeks, ~d days, ~d hours, ~d minutes, and ~d seconds~n', Ns),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hourm1sec = [0,0,1,0,-1], % 1 second less than 1 hour
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('1 second less than 1 hour ~w = ~w = ~d seconds~n',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Hourm1sec,Nd,Secs]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ym1sec = [364,0,0,-1], % 1 year - 1 second, but 7*52 = 364
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('1 second less than 1 year in days and time:        ~w~n',[Ym1sec]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('1 second less than 1 year in weeks, days and time: ~w~n',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Yw]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('                    7 weekdays * 52 weeks in days: 364~n',[]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('1 second less than 1 year in seconds:              ~d~n',[S]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;% Pounds, shillings, pence
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('~d £, ~d shillings, and ~d pence are ~d pence total~n',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[8,12,10,Pence]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('~d pence are ~d £, ~d shillings, and ~d pence~n',[Pence|Ps]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;% Degrees, minutes, seconds
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('53 degrees 45''20'''' W is ~d seconds west~n',[Seconds]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;% Binary numbers
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('67 in a binary (octet) is ~w~n',[B]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('7F hexadecimal is ~d decimal~n', [Hx]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format('254 decimal is ~w hexadecimal~n', [Hx1]),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;halt.

mixed_radix_number(Rs, Ns, S) :- nonvar(Ns), !,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reverse(Rs, Rs1),

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S1 is R * S0 + N,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rem is S mod R,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S1 is floor(S / R),
```
9. Dennis Decker Jensen said

Have mercy, this does not bode well, 3rd time:

```:- initialization(main).

main :-
% Weeks, days, hours, minutes, seconds
Number is 7*24*60*60-1, % 1 second less than 1 week
format('~d weeks, ~d days, ~d hours, ~d minutes, and ~d seconds~n', Ns),
Hourm1sec = [0,0,1,0,-1], % 1 second less than 1 hour
format('1 second less than 1 hour ~w = ~w = ~d seconds~n',
[Hourm1sec,Nd,Secs]),
Ym1sec = [364,0,0,-1], % 1 year - 1 second, but 7*52 = 364
format('1 second less than 1 year in days and time:        ~w~n',[Ym1sec]),
format('1 second less than 1 year in weeks, days and time: ~w~n',
[Yw]),
format('                    7 weekdays * 52 weeks in days: 364~n',[]),
format('1 second less than 1 year in seconds:              ~d~n',[S]),
% Pounds, shillings, pence
format('~d £, ~d shillings, and ~d pence are ~d pence total~n',
[8,12,10,Pence]),
format('~d pence are ~d £, ~d shillings, and ~d pence~n',[Pence|Ps]),
% Degrees, minutes, seconds
format('53 degrees 45''20'''' W is ~d seconds west~n',[Seconds]),
% Binary numbers
format('67 in a binary (octet) is ~w~n',[B]),
format('7F hexadecimal is ~d decimal~n', [Hx]),
format('254 decimal is ~w hexadecimal~n', [Hx1]),
halt.

mixed_radix_number(Rs, Ns, S) :- nonvar(Ns), !,
reverse(Rs, Rs1),