#include "num.h"

Num::Num(int value, int modulo): value(value % modulo), modulo(modulo) {}
Num &Num::operator=(const Num &other) = default;
Num Num::operator+(const Num &other) {
  int m = this->modulo > other.modulo ? this->modulo : other.modulo;
  int v;
  if (this->value > m - other.value) {
    v = this->value - (m - other.value);
  } else {
    v = (this->value + other.value) % m;
  }
  return Num(v, m);
}
Num Num::operator-(const Num &other) {
  int m = this->modulo > other.modulo ? this->modulo : other.modulo;
  int v = (this->value - other.value) % m;
  if (v < 0) {
    v = m + v;
  }
  return Num(v, m);
}
Num Num::operator*(const Num &other) {
  int m = this->modulo > other.modulo ? this->modulo : other.modulo;
  unsigned long v;
  if (this->value < 0) {
    v = this->modulo - this->value;
  } else {
    v = this->value;
  }
  if (other.value < 0) {
    v *= (other.modulo - other.value);
  } else {
    v *= other.value;
  }
  v %= m;
  return Num(v, m);
}
Num Num::operator+(int num) {
  num %= this->modulo;
  int v;
  if (this->value > this->modulo - num) {
    v = this->value - (this->modulo - num);
  } else {
    v = (this->value + num) % this->modulo;
  }
  return Num(v, this->modulo);
}
Num Num::operator-(int num) {
  num %= this->modulo;
  int v = (this->value - num) % this->modulo;
  if (v < 0) {
    v = this->modulo + v;
  }
  return Num(v, this->modulo);
}
Num Num::operator*(int num) {
  num %= modulo;
  unsigned long v;
  if (this->value < 0) {
    v = this->modulo - this->value;
  } else {
    v = this->value;
  }
  if (num < 0) {
    v *= (num - this->value);
  } else {
    v *= num;
  }
  v %= this->modulo;
  return Num(v, this->modulo);
}
Num &Num::operator+=(const Num &other) {
  this->modulo = this->modulo > other.modulo ? this->modulo : other.modulo;
  if (this->value > this->modulo - other.value) {
    this->value = this->value - (this->modulo - other.value);
  } else {
    this->value = (this->value + other.value) % this->modulo;
  }
  return *this;
}
Num &Num::operator-=(const Num &other) {
  this->modulo = this->modulo > other.modulo ? this->modulo : other.modulo;
  this->value = (this->value - other.value) % this->modulo;
  if (this->value < 0) {
    this->value = this->modulo + this->value;
  }
  return *this;
}
Num &Num::operator*=(const Num &other) {
  this->modulo = this->modulo > other.modulo ? this->modulo : other.modulo;
  unsigned long v;
  if (this->value < 0) {
    v = this->modulo - this->value;
  } else {
    v = this->value;
  }
  if (other.value < 0) {
    v *= (other.modulo - other.value);
  } else {
    v *= other.value;
  }
  this->value = v % this->modulo;
  return *this;
}
Num &Num::operator+=(int num) {
  num %= this->modulo;
  if (this->value > this->modulo - num) {
    this->value = this->value - (this->modulo - num);
  } else {
    this->value = (this->value + num) % this->modulo;
  }
  return *this;
}
Num &Num::operator-=(int num) {
  num %= this->modulo;
  this->value = (this->value - num) % this->modulo;
  if (this->value < 0) {
    this->value = this->modulo + this->value;
  }
  return *this;
}
Num &Num::operator*=(int num) {
  num %= modulo;
  unsigned long v;
  if (this->value < 0) {
    v = this->modulo - this->value;
  } else {
    v = this->value;
  }
  if (num < 0) {
    v *= (num - this->value);
  } else {
    v *= num;
  }
  this->value = v % this->modulo;
  return *this;
}