Skip to content

Instantly share code, notes, and snippets.

@Kludgy
Created June 28, 2016 20:33
Show Gist options
  • Save Kludgy/532a934c0f4cca2c52376b8f015af10a to your computer and use it in GitHub Desktop.
Save Kludgy/532a934c0f4cca2c52376b8f015af10a to your computer and use it in GitHub Desktop.
Defining subtraction in terms of conjugation of integers-modulo-n
/*
Consider the solution for adding months (o) to a date consisting of the month (m) and year (y):
Let
o >= 0
1 <= m <= 12
y > 0
So that new date is given by,
y' = [(m + o - 1) div 12] + y
m' = [(m + o - 1) rem 12] + 1
'rem' and 'div' are remainder and integer division, respectively.
In C++ operating over the positive field of integers, 'rem' can be replaced with integer
modulus '%' and 'div' can be replaced with division '/' over integer types.
y' = ((m + o - 1) / 12) + y
m' = ((m + o - 1) % 12) + 1
Perhaps it stands to reason that some conjugation of the date will 'flip the number line'
so that addition becomes subtraction. In this case it can be imagined that there is some
invertible relation (F and its inverse Fi) for which the subtraction of months is given by,
y' = Fi( ((m + F(o) - 1) / 12) + y )
m' = Fi( ((m + F(o) - 1) % 12) + 1 )
Picking the 0-offset (k) and period (T) to define the complementary number line gives us
the involution F,
F(x) = Fi(x) = k + T(x) - x
This has the desired property of flipping the number line modulo T. For example in months,
Let,
k = 1
1 <= m <= 12
T(m) = 12
Then,
F(m) = Fi(m) = 1 + 12 - m
Does this work?
*/
#include <stdint.h>
#include <assert.h>
#include <iostream>
#include <vector>
struct YearMonth
{
uint16_t year;
uint16_t month;
YearMonth(uint16_t year, uint16_t month)
: year(year), month(month) {}
};
YearMonth Conjugate(YearMonth date) // F s.t. F(F(x))=x
{
return YearMonth(
uint16_t(0 + 0xffff - date.year ), // k=0, T=0xffff
uint16_t(1 + 12 - date.month)); // k=1, T=12
}
YearMonth AddMonths(YearMonth date, uint16_t numMonths)
{
const uint32_t p = date.month + numMonths - 1;
return YearMonth(
uint16_t(p / 12 + date.year),
uint16_t(p % 12 + 1));
}
YearMonth SubMonths(YearMonth date, uint16_t numMonths)
{
return Conjugate(AddMonths(Conjugate(date), numMonths));
}
std::ostream& operator <<(std::ostream& os, YearMonth date)
{
return os << "{ year=" << date.year << ",month=" << date.month << " }\n";
}
int main()
{
const YearMonth a(2000, 1);
const int n = 8;
const YearMonth v[n] = {
AddMonths(a, 12), SubMonths(a, 12),
AddMonths(a, 13), SubMonths(a, 13),
AddMonths(a, 11), SubMonths(a, 11),
AddMonths(a, 1), SubMonths(a, 1) };
for (int i = 0; i < n; ++i) std::cout << v[i];
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment