diff options
| -rw-r--r-- | test-suite/output/QArithSyntax.out | 90 | ||||
| -rw-r--r-- | test-suite/output/QArithSyntax.v | 34 | ||||
| -rw-r--r-- | theories/Init/Decimal.v | 6 | ||||
| -rw-r--r-- | theories/Init/Hexadecimal.v | 38 | ||||
| -rw-r--r-- | theories/Numbers/DecimalQ.v | 2 | ||||
| -rw-r--r-- | theories/Numbers/HexadecimalQ.v | 2 | ||||
| -rw-r--r-- | theories/QArith/QArith_base.v | 285 |
7 files changed, 329 insertions, 128 deletions
diff --git a/test-suite/output/QArithSyntax.out b/test-suite/output/QArithSyntax.out index 9b5c076cb4..ced52524f2 100644 --- a/test-suite/output/QArithSyntax.out +++ b/test-suite/output/QArithSyntax.out @@ -1,26 +1,72 @@ eq_refl : 1.02 = 1.02 : 1.02 = 1.02 -eq_refl : 10.2 = 10.2 - : 10.2 = 10.2 -eq_refl : 1020 = 1020 - : 1020 = 1020 -eq_refl : 102 = 102 - : 102 = 102 -eq_refl : 1.02 = 1.02 - : 1.02 = 1.02 -eq_refl : -1e-4 = -1e-4 - : -1e-4 = -1e-4 +1.02e1 + : Q +10.2 + : Q +1.02e3 + : Q +1020 + : Q +1.02e2 + : Q +102 + : Q +eq_refl : 10.2e-1 = 1.02 + : 10.2e-1 = 1.02 +eq_refl : -0.0001 = -0.0001 + : -0.0001 = -0.0001 eq_refl : -0.50 = -0.50 : -0.50 = -0.50 -eq_refl : -26 = -26 - : -26 = -26 -eq_refl : 2860 # 256 = 2860 # 256 - : 2860 # 256 = 2860 # 256 -eq_refl : -6882 = -6882 - : -6882 = -6882 -eq_refl : 2860 # 64 = 2860 # 64 - : 2860 # 64 = 2860 # 64 -eq_refl : 2860 = 2860 - : 2860 = 2860 -eq_refl : -2860 # 1024 = -2860 # 1024 - : -2860 # 1024 = -2860 # 1024 +0 + : Q +0 + : Q +42 + : Q +42 + : Q +1.23 + : Q +0x1.23%xQ + : Q +0.0012 + : Q +42e3 + : Q +42e-3 + : Q +eq_refl : -0x1a = -0x1a + : -0x1a = -0x1a +eq_refl : 0xb.2c = 0xb.2c + : 0xb.2c = 0xb.2c +eq_refl : -0x1ae2 = -0x1ae2 + : -0x1ae2 = -0x1ae2 +0xb.2cp2 + : Q +2860 # 64 + : Q +0xb.2cp8 + : Q +0xb2c + : Q +eq_refl : -0xb.2cp-2 = -2860 # 1024 + : -0xb.2cp-2 = -2860 # 1024 +0x0 + : Q +0x0 + : Q +0x2a + : Q +0x2a + : Q +1.23%Q + : Q +0x1.23 + : Q +0x0.0012 + : Q +0x2ap3 + : Q +0x2ap-3 + : Q diff --git a/test-suite/output/QArithSyntax.v b/test-suite/output/QArithSyntax.v index b5c6222bba..e979abca66 100644 --- a/test-suite/output/QArithSyntax.v +++ b/test-suite/output/QArithSyntax.v @@ -1,15 +1,39 @@ Require Import QArith. Open Scope Q_scope. Check (eq_refl : 1.02 = 102 # 100). -Check (eq_refl : 1.02e1 = 102 # 10). -Check (eq_refl : 1.02e+03 = 1020). -Check (eq_refl : 1.02e+02 = 102 # 1). +Check 1.02e1. +Check 102 # 10. +Check 1.02e+03. +Check 1020. +Check 1.02e+02. +Check 102 # 1. Check (eq_refl : 10.2e-1 = 1.02). Check (eq_refl : -0.0001 = -1 # 10000). Check (eq_refl : -0.50 = - 50 # 100). +Check 0. +Check 000. +Check 42. +Check 0x2a. +Check 1.23. +Check 0x1.23. +Check 0.0012. +Check 42e3. +Check 42e-3. +Open Scope hex_Q_scope. Check (eq_refl : -0x1a = - 26 # 1). Check (eq_refl : 0xb.2c = 2860 # 256). Check (eq_refl : -0x1ae2 = -6882). -Check (eq_refl : 0xb.2cp2 = 2860 # 64). -Check (eq_refl : 0xb.2cp8 = 2860). +Check 0xb.2cp2. +Check 2860 # 64. +Check 0xb.2cp8. +Check 2860. Check (eq_refl : -0xb.2cp-2 = -2860 # 1024). +Check 0x0. +Check 0x00. +Check 42. +Check 0x2a. +Check 1.23. +Check 0x1.23. +Check 0x0.0012. +Check 0x2ap3. +Check 0x2ap-3. diff --git a/theories/Init/Decimal.v b/theories/Init/Decimal.v index 025264ab01..bb12f9ca3e 100644 --- a/theories/Init/Decimal.v +++ b/theories/Init/Decimal.v @@ -118,6 +118,12 @@ Definition opp (d:int) := | Neg d => Pos d end. +Definition abs (d:int) : uint := + match d with + | Pos d => d + | Neg d => d + end. + (** For conversions with binary numbers, it is easier to operate on little-endian numbers. *) diff --git a/theories/Init/Hexadecimal.v b/theories/Init/Hexadecimal.v index 36f5e5ad1f..7467aa1262 100644 --- a/theories/Init/Hexadecimal.v +++ b/theories/Init/Hexadecimal.v @@ -125,6 +125,12 @@ Definition opp (d:int) := | Neg d => Pos d end. +Definition abs (d:int) : uint := + match d with + | Pos d => d + | Neg d => d + end. + (** For conversions with binary numbers, it is easier to operate on little-endian numbers. *) @@ -173,6 +179,38 @@ Definition nztail_int d := | Neg d => let (r, n) := nztail d in pair (Neg r) n end. +(** [del_head n d] removes [n] digits at beginning of [d] + or returns [zero] if [d] has less than [n] digits. *) + +Fixpoint del_head n d := + match n with + | O => d + | S n => + match d with + | Nil => zero + | D0 d | D1 d | D2 d | D3 d | D4 d | D5 d | D6 d | D7 d | D8 d | D9 d + | Da d | Db d | Dc d | Dd d | De d | Df d => + del_head n d + end + end. + +Definition del_head_int n d := + match d with + | Pos d => del_head n d + | Neg d => del_head n d + end. + +(** [del_tail n d] removes [n] digits at end of [d] + or returns [zero] if [d] has less than [n] digits. *) + +Definition del_tail n d := rev (del_head n (rev d)). + +Definition del_tail_int n d := + match d with + | Pos d => Pos (del_tail n d) + | Neg d => Neg (del_tail n d) + end. + Module Little. (** Successor of little-endian numbers *) diff --git a/theories/Numbers/DecimalQ.v b/theories/Numbers/DecimalQ.v index d2cd061594..f666c29643 100644 --- a/theories/Numbers/DecimalQ.v +++ b/theories/Numbers/DecimalQ.v @@ -15,7 +15,7 @@ Require Import Decimal DecimalFacts DecimalPos DecimalN DecimalZ QArith. -Lemma of_to (q:Q) : forall d, to_decimal q = Some d -> of_decimal d = q. +Lemma of_to (q:IQ) : forall d, to_decimal q = Some d -> of_decimal d = q. Admitted. (* normalize without fractional part, for instance norme 12.3e-1 is 123e-2 *) diff --git a/theories/Numbers/HexadecimalQ.v b/theories/Numbers/HexadecimalQ.v index ce6f074d70..b773aede8c 100644 --- a/theories/Numbers/HexadecimalQ.v +++ b/theories/Numbers/HexadecimalQ.v @@ -16,7 +16,7 @@ Require Import Decimal DecimalFacts DecimalPos DecimalN DecimalZ. Require Import Hexadecimal HexadecimalFacts HexadecimalPos HexadecimalN HexadecimalZ QArith. -Lemma of_to (q:Q) : forall d, to_hexadecimal q = Some d -> of_hexadecimal d = q. +Lemma of_to (q:IQ) : forall d, to_hexadecimal q = Some d -> of_hexadecimal d = q. Admitted. (* normalize without fractional part, for instance norme 0x1.2p-1 is 0x12e-5 *) diff --git a/theories/QArith/QArith_base.v b/theories/QArith/QArith_base.v index 151355519e..9a70ac311a 100644 --- a/theories/QArith/QArith_base.v +++ b/theories/QArith/QArith_base.v @@ -18,6 +18,9 @@ Require Export Morphisms Setoid Bool. Record Q : Set := Qmake {Qnum : Z; Qden : positive}. +Declare Scope hex_Q_scope. +Delimit Scope hex_Q_scope with xQ. + Declare Scope Q_scope. Delimit Scope Q_scope with Q. Bind Scope Q_scope with Q. @@ -33,104 +36,6 @@ Ltac simpl_mult := rewrite ?Pos2Z.inj_mul. 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 := - (* choose between 123e-2 and 1.23, this is purely heuristic - and doesn't play any soundness role *) - let choose_exponent i ne := - let i := match i with Decimal.Pos i | Decimal.Neg i => i end in - let li := Decimal.nb_digits i in - let le := Decimal.nb_digits (Nat.to_uint ne) in - Nat.ltb (Nat.add li le) ne in - (* print 123 / 100 as 123e-2 *) - let decimal_exponent i ne := - let e := Z.to_int (Z.opp (Z.of_nat ne)) in - Decimal.DecimalExp i Decimal.Nil e in - (* print 123 / 100 as 1.23 *) - let decimal_dot i ne := - let ai := match i with Decimal.Pos i | Decimal.Neg i => i end in - let ni := Decimal.nb_digits ai in - if Nat.ltb ne ni then - let i := Decimal.del_tail_int ne i in - let f := Decimal.del_head (Nat.sub ni ne) ai in - Decimal.Decimal i f - else - let z := match i with - | Decimal.Pos _ => Decimal.Pos (Decimal.zero) - | Decimal.Neg _ => Decimal.Neg (Decimal.zero) end in - Decimal.Decimal z (Nat.iter (Nat.sub ne ni) Decimal.D0 ai) in - 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 e_den with - | O => Some (Decimal.Decimal num Decimal.Nil) - | ne => - if choose_exponent num ne then Some (decimal_exponent num ne) - else Some (decimal_dot num ne) - end - | _ => None - end. - -Definition of_hexadecimal (d:Hexadecimal.hexadecimal) : Q := - 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 e := Z.sub (Z.of_int e) (Z.mul 4 (Z.of_nat (Hexadecimal.nb_digits f))) in - match e with - | Z0 => Qmake num 1 - | Zpos e => Qmake (Pos.iter (Z.mul 2) num e) 1 - | Zneg e => Qmake num (Pos.iter (Pos.mul 2) 1%positive e) - end. - -Definition to_hexadecimal (q:Q) : option Hexadecimal.hexadecimal := - let mk_exp i e := - Hexadecimal.HexadecimalExp i Hexadecimal.Nil (Z.to_int (Z.opp e)) in - let num := Z.to_hex_int (Qnum q) in - let (den, e_den) := Hexadecimal.nztail (Pos.to_hex_uint (Qden q)) in - let e := Z.of_nat e_den in - match den with - | Hexadecimal.D1 Hexadecimal.Nil => - match e_den with - | O => Some (Hexadecimal.Hexadecimal num Hexadecimal.Nil) - | _ => Some (mk_exp num (4 * e)%Z) - end - | Hexadecimal.D2 Hexadecimal.Nil => Some (mk_exp num (1 + 4 * e)%Z) - | Hexadecimal.D4 Hexadecimal.Nil => Some (mk_exp num (2 + 4 * e)%Z) - | Hexadecimal.D8 Hexadecimal.Nil => Some (mk_exp num (3 + 4 * e)%Z) - | _ => None - end. - -Definition of_numeral (d:Number.number) : option Q := - match d with - | Number.Dec d => Some (of_decimal d) - | Number.Hex d => Some (of_hexadecimal d) - end. - -Definition to_numeral (q:Q) : option Number.number := - match to_decimal q with - | None => None - | Some q => Some (Number.Dec q) - end. - -Number Notation Q of_numeral to_numeral : Q_scope. - Definition inject_Z (x : Z) := Qmake x 1. Arguments inject_Z x%Z. @@ -316,7 +221,7 @@ Definition Qminus (x y : Q) := Qplus x (Qopp y). Definition Qinv (x : Q) := match Qnum x with - | Z0 => 0 + | Z0 => 0#1 | Zpos p => (QDen x)#p | Zneg p => (Zneg (Qden x))#p end. @@ -335,6 +240,188 @@ 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.Dec d => of_decimal d + | Number.Hex h => of_hexadecimal h + end. + +Definition to_number (q:IQ) : option Number.number := + match to_decimal q with + | None => None + | Some q => Some (Number.Dec q) + end. + +Definition to_hex_number q := + match to_hexadecimal q with + | None => None + | Some q => Some (Number.Hex 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] *) Lemma Qmake_Qdiv a b : a#b==inject_Z a/inject_Z (Zpos b). |
