(************************************************************************)
(*         *   The Coq Proof Assistant / The Coq Development Team       *)
(*  v      *   INRIA, CNRS and contributors - Copyright 1999-2018       *)
(* <O___,, *       (see CREDITS file for the list of authors)           *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)
Require Export ZArith.
Require Export ZArithRing.
Require Export Morphisms Setoid Bool.
(** * Definition of [Q] and basic properties *)
(** Rationals are pairs of [Z] and [positive] numbers. *)
Record Q : Set := Qmake {Qnum : Z; Qden : positive}.
Declare Scope Q_scope.
Delimit Scope Q_scope with Q.
Bind Scope Q_scope with Q.
Arguments Qmake _%Z _%positive.
Open Scope Q_scope.
Ltac simpl_mult := rewrite ?Pos2Z.inj_mul.
(** [a#b] denotes the fraction [a] over [b]. *)
Notation "a # b" := (Qmake a b) (at level 55, no associativity) : Q_scope.
Definition of_decimal (d:Decimal.decimal) : Q :=
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 e := Z.sub (Z.of_int e) (Z.of_nat (Decimal.nb_digits f)) in
match e with
| Z0 => Qmake num 1
| Zpos e => Qmake (Pos.iter (Z.mul 10) num e) 1
| Zneg e => Qmake num (Pos.iter (Pos.mul 10) 1%positive e)
end.
Definition to_decimal (q:Q) : option Decimal.decimal :=
let num := Z.to_int (Qnum q) in
let (den, e_den) := Decimal.nztail (Pos.to_uint (Qden q)) in
match den with
| Decimal.D1 Decimal.Nil =>
match Z.of_nat e_den with
| Z0 => Some (Decimal.Decimal num Decimal.Nil)
| e => Some (Decimal.DecimalExp num Decimal.Nil (Z.to_int (Z.opp e)))
end
| _ => None
end.
Numeral Notation Q of_decimal to_decimal : Q_scope.
Definition inject_Z (x : Z) := Qmake x 1.
Arguments inject_Z x%Z.
Notation QDen p := (Zpos (Qden p)).
Definition Qeq (p q : Q) := (Qnum p * QDen q)%Z = (Qnum q * QDen p)%Z.
Definition Qle (x y : Q) := (Qnum x * QDen y <= Qnum y * QDen x)%Z.
Definition Qlt (x y : Q) := (Qnum x * QDen y < Qnum y * QDen x)%Z.
Notation Qgt a b := (Qlt b a) (only parsing).
Notation Qge a b := (Qle b a) (only parsing).
Infix "==" := Qeq (at level 70, no associativity) : Q_scope.
Infix "<" := Qlt : Q_scope.
Infix "<=" := Qle : Q_scope.
Notation "x > y" := (Qlt y x)(only parsing) : Q_scope.
Notation "x >= y" := (Qle y x)(only parsing) : Q_scope.
Notation "x <= y <= z" := (x<=y/\y<=z) : Q_scope.
(** injection from Z is injective. *)
(** Another approach : using Qcompare for defining order relations. *)
Definition Qcompare (p q : Q) := (Qnum p * QDen q ?= Qnum q * QDen p)%Z.
Notation "p ?= q" := (Qcompare p q) : Q_scope.
Hint Unfold Qeq Qlt Qle : qarith.
Hint Extern 5 (?X1 <> ?X2) => intro; discriminate: qarith.

Lemma Qcompare_spec x y : CompareSpec (x==y) (x<y) (y<x) (x ?= y).