(** * 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.
Register Qplus  as rat.Q.Qplus.
Register Qminus as rat.Q.Qminus.
Register Qopp   as rat.Q.Qopp.
Register Qmult  as rat.Q.Qmult.
(** 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.
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.
Number Notation Q of_number to_hex_number (via IQ
mapping [Qmake => IQmake, Qmult => IQmult, Qdiv => IQdiv,
Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
: hex_Q_scope.
Number Notation Q of_number to_number (via IQ
mapping [Qmake => IQmake, Qmult => IQmult, Qdiv => IQdiv,
Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
: Q_scope.
(** A light notation for [Zpos] *)

(* Specifications: *)
Lemma Qmake_Qdiv a b : a#b==inject_Z a/inject_Z (Zpos b).
#[global]
Instance Qplus_comp : Proper (Qeq==>Qeq==>Qeq) Qplus.