(** * Addition, multiplication and opposite *)

(** The addition, multiplication and opposite are defined
   in the straightforward way: *)

Definition Qplus (x y : Q) :=
  (Qnum x * QDen y + Qnum y * QDen x) # (Qden x * Qden y).Definition Qmult (x y : Q) := (Qnum x * Qnum y) # (Qden x * Qden y).Definition Qopp (x : Q) := (- Qnum x) # (Qden x).Definition Qminus (x y : Q) := Qplus x (Qopp y).Definition Qinv (x : Q) :=
  match Qnum x with
  | Z0 => 0#1
  | Zpos p => (QDen x)#p
  | Zneg p => (Zneg (Qden x))#p
  end.Definition Qdiv (x y : Q) := Qmult x (Qinv y).Infix "+" := Qplus : Q_scope.Notation "- x" := (Qopp x) : Q_scope.Infix "-" := Qminus : Q_scope.Infix "*" := Qmult : Q_scope.Notation "/ x" := (Qinv x) : Q_scope.Infix "/" := Qdiv : Q_scope.(** Number notation for constants *)

Inductive IZ :=
  | IZpow_pos : Z -> positive -> IZ
  | IZ0 : IZ
  | IZpos : positive -> IZ
  | IZneg : positive -> IZ.(** Number notation for constants *)

Inductive IZ :=
  | IZpow_pos : Z -> positive -> IZ
  | IZ0 : IZ
  | IZpos : positive -> IZ
  | IZneg : positive -> IZ.(** Number notation for constants *)

Inductive IZ :=
  | IZpow_pos : Z -> positive -> IZ
  | IZ0 : IZ
  | IZpos : positive -> IZ
  | IZneg : positive -> IZ.(** Number notation for constants *)

Inductive IZ :=
  | IZpow_pos : Z -> positive -> IZ
  | IZ0 : IZ
  | IZpos : positive -> IZ
  | IZneg : positive -> IZ.(** Number notation for constants *)

Inductive IZ :=
  | IZpow_pos : Z -> positive -> IZ
  | IZ0 : IZ
  | IZpos : positive -> IZ
  | IZneg : positive -> IZ.Inductive IQ :=
  | IQmake : IZ -> positive -> IQ
  | IQmult : IQ -> IQ -> IQ
  | IQdiv : IQ -> IQ -> IQ.Inductive IQ :=
  | IQmake : IZ -> positive -> IQ
  | IQmult : IQ -> IQ -> IQ
  | IQdiv : IQ -> IQ -> IQ.Inductive IQ :=
  | IQmake : IZ -> positive -> IQ
  | IQmult : IQ -> IQ -> IQ
  | IQdiv : IQ -> IQ -> IQ.Inductive IQ :=
  | IQmake : IZ -> positive -> IQ
  | IQmult : IQ -> IQ -> IQ
  | IQdiv : IQ -> IQ -> IQ.Definition IZ_of_Z z :=
  match z with
  | Z0 => IZ0
  | Zpos e => IZpos e
  | Zneg e => IZneg e
  end.Definition IZ_to_Z z :=
  match z with
  | IZ0 => Some Z0
  | IZpos e => Some (Zpos e)
  | IZneg e => Some (Zneg e)
  | IZpow_pos _ _ => None
  end.Definition of_decimal (d:Decimal.decimal) : IQ :=
  let '(i, f, e) :=
    match d with
    | Decimal.Decimal i f => (i, f, Decimal.Pos Decimal.Nil)
    | Decimal.DecimalExp i f e => (i, f, e)
    end in
  let num := Z.of_int (Decimal.app_int i f) in
  let den := Nat.iter (Decimal.nb_digits f) (Pos.mul 10) 1%positive in
  let q := IQmake (IZ_of_Z num) den in
  let e := Z.of_int e in
  match e with
  | Z0 => q
  | Zpos e => IQmult q (IQmake (IZpow_pos 10 e) 1)
  | Zneg e => IQdiv q (IQmake (IZpow_pos 10 e) 1)
  end.Definition IQmake_to_decimal num den :=
  let num := Z.to_int num in
  let (den, e_den) := Decimal.nztail (Pos.to_uint den) in
  match den with
  | Decimal.D1 Decimal.Nil =>
    match e_den with
    | O => Some (Decimal.Decimal num Decimal.Nil)
    | ne =>
      let ai := Decimal.abs num in
      let ni := Decimal.nb_digits ai in
      if Nat.ltb ne ni then
        let i := Decimal.del_tail_int ne num in
        let f := Decimal.del_head (Nat.sub ni ne) ai in
        Some (Decimal.Decimal i f)
      else
        let z := match num with
          | Decimal.Pos _ => Decimal.Pos (Decimal.zero)
          | Decimal.Neg _ => Decimal.Neg (Decimal.zero) end in
        Some (Decimal.Decimal z (Nat.iter (Nat.sub ne ni) Decimal.D0 ai))
    end
  | _ => None
  end.Definition IQmake_to_decimal' num den :=
  match IZ_to_Z num with
  | None => None
  | Some num => IQmake_to_decimal num den
  end.Definition to_decimal (n : IQ) : option Decimal.decimal :=
  match n with
  | IQmake num den => IQmake_to_decimal' num den
  | IQmult (IQmake num den) (IQmake (IZpow_pos 10 e) 1) =>
    match IQmake_to_decimal' num den with
    | Some (Decimal.Decimal i f) =>
      Some (Decimal.DecimalExp i f (Pos.to_int e))
    | _ => None
    end
  | IQdiv (IQmake num den) (IQmake (IZpow_pos 10 e) 1) =>
    match IQmake_to_decimal' num den with
    | Some (Decimal.Decimal i f) =>
      Some (Decimal.DecimalExp i f (Decimal.Neg (Pos.to_uint e)))
    | _ => None
    end
  | _ => None
  end.Definition of_hexadecimal (d:Hexadecimal.hexadecimal) : IQ :=
  let '(i, f, e) :=
    match d with
    | Hexadecimal.Hexadecimal i f => (i, f, Decimal.Pos Decimal.Nil)
    | Hexadecimal.HexadecimalExp i f e => (i, f, e)
    end in
  let num := Z.of_hex_int (Hexadecimal.app_int i f) in
  let den := Nat.iter (Hexadecimal.nb_digits f) (Pos.mul 16) 1%positive in
  let q := IQmake (IZ_of_Z num) den in
  let e := Z.of_int e in
  match e with
  | Z0 => q
  | Zpos e => IQmult q (IQmake (IZpow_pos 2 e) 1)
  | Zneg e => IQdiv q (IQmake (IZpow_pos 2 e) 1)
  end.Definition IQmake_to_hexadecimal num den :=
  let num := Z.to_hex_int num in
  let (den, e_den) := Hexadecimal.nztail (Pos.to_hex_uint den) in
  match den with
  | Hexadecimal.D1 Hexadecimal.Nil =>
    match e_den with
    | O => Some (Hexadecimal.Hexadecimal num Hexadecimal.Nil)
    | ne =>
      let ai := Hexadecimal.abs num in
      let ni := Hexadecimal.nb_digits ai in
      if Nat.ltb ne ni then
        let i := Hexadecimal.del_tail_int ne num in
        let f := Hexadecimal.del_head (Nat.sub ni ne) ai in
        Some (Hexadecimal.Hexadecimal i f)
      else
        let z := match num with
          | Hexadecimal.Pos _ => Hexadecimal.Pos (Hexadecimal.zero)
          | Hexadecimal.Neg _ => Hexadecimal.Neg (Hexadecimal.zero) end in
        Some (Hexadecimal.Hexadecimal z (Nat.iter (Nat.sub ne ni) Hexadecimal.D0 ai))
    end
  | _ => None
  end.Definition IQmake_to_hexadecimal' num den :=
  match IZ_to_Z num with
  | None => None
  | Some num => IQmake_to_hexadecimal num den
  end.Definition to_hexadecimal (n : IQ) : option Hexadecimal.hexadecimal :=
  match n with
  | IQmake num den => IQmake_to_hexadecimal' num den
  | IQmult (IQmake num den) (IQmake (IZpow_pos 2 e) 1) =>
    match IQmake_to_hexadecimal' num den with
    | Some (Hexadecimal.Hexadecimal i f) =>
      Some (Hexadecimal.HexadecimalExp i f (Pos.to_int e))
    | _ => None
    end
  | IQdiv (IQmake num den) (IQmake (IZpow_pos 2 e) 1) =>
    match IQmake_to_hexadecimal' num den with
    | Some (Hexadecimal.Hexadecimal i f) =>
      Some (Hexadecimal.HexadecimalExp i f (Decimal.Neg (Pos.to_uint e)))
    | _ => None
    end
  | _ => None
  end.Definition of_number (n : Number.number) : IQ :=
  match n with
  | Number.Decimal d => of_decimal d
  | Number.Hexadecimal h => of_hexadecimal h
  end.Definition to_number (q:IQ) : option Number.number :=
  match to_decimal q with
  | None => None
  | Some q => Some (Number.Decimal q)
  end.Definition to_hex_number q :=
  match to_hexadecimal q with
  | None => None
  | Some q => Some (Number.Hexadecimal q)
  end.

Lemma Qmake_Qdiv a b : a#b==inject_Z a/inject_Z (Zpos b).