# HG changeset patch # User haftmann # Date 1660768636 0 # Node ID 48d0320357449414e9591059303d4454ddbd92c7 # Parent 77cbf472fcc9e2b0c3c977590b2e6c9bfdaa2e47 streamlined primitive definitions for integer division diff -r 77cbf472fcc9 -r 48d032035744 NEWS --- a/NEWS Thu Aug 18 09:29:11 2022 +0200 +++ b/NEWS Wed Aug 17 20:37:16 2022 +0000 @@ -39,7 +39,7 @@ * New Theory Code_Abstract_Char implements characters by target language integers, sacrificing pattern patching in exchange for dramatically -increased performance for comparisions. +increased performance for comparisons. * New theory HOL-Library.NList of fixed length lists @@ -49,6 +49,9 @@ * Theory "HOL.Bit_Operations": rule bit_0 is not default [simp] any longer. INCOMPATIBILITY. +* Streamlined primitive definitions of division and modulus on integers. +INCOMPATIBILITY. + * Theory "HOL.Fun": - Added predicate monotone_on and redefined monotone to be an abbreviation. Lemma monotone_def is explicitly provided for backward diff -r 77cbf472fcc9 -r 48d032035744 src/HOL/Bit_Operations.thy --- a/src/HOL/Bit_Operations.thy Thu Aug 18 09:29:11 2022 +0200 +++ b/src/HOL/Bit_Operations.thy Wed Aug 17 20:37:16 2022 +0000 @@ -7,6 +7,15 @@ imports Presburger Groups_List begin +lemma half_nonnegative_int_iff [simp]: + \k div 2 \ 0 \ k \ 0\ for k :: int + by auto + +lemma half_negative_int_iff [simp]: + \k div 2 < 0 \ k < 0\ for k :: int + by auto + + subsection \Abstract bit structures\ class semiring_bits = semiring_parity + @@ -1465,7 +1474,7 @@ lemma not_int_div_2: \NOT k div 2 = NOT (k div 2)\ for k :: int - by (cases k) (simp_all add: not_int_def divide_int_def nat_add_distrib) + by (simp add: not_int_def) lemma bit_not_int_iff: \bit (NOT k) n \ \ bit k n\ @@ -1729,7 +1738,7 @@ case (odd k) from odd.IH [of \l div 2\] odd.hyps odd.prems show ?case - by (simp add: and_int_rec [of _ l]) linarith + by (simp add: and_int_rec [of _ l]) qed lemma or_nonnegative_int_iff [simp]: @@ -1754,7 +1763,7 @@ case (even k) from even.IH [of \l div 2\] even.hyps even.prems show ?case - by (simp add: or_int_rec [of _ l]) linarith + by (simp add: or_int_rec [of _ l]) next case (odd k) from odd.IH [of \l div 2\] odd.hyps odd.prems @@ -2173,22 +2182,6 @@ \\ 2 ^ n \ (0::int)\ by (simp add: power_le_zero_eq) -lemma half_nonnegative_int_iff [simp]: - \k div 2 \ 0 \ k \ 0\ for k :: int -proof (cases \k \ 0\) - case True - then show ?thesis - by (auto simp add: divide_int_def sgn_1_pos) -next - case False - then show ?thesis - by (auto simp add: divide_int_def not_le elim!: evenE) -qed - -lemma half_negative_int_iff [simp]: - \k div 2 < 0 \ k < 0\ for k :: int - by (subst Not_eq_iff [symmetric]) (simp add: not_less) - lemma int_bit_bound: fixes k :: int obtains n where \\m. n \ m \ bit k m \ bit k n\ diff -r 77cbf472fcc9 -r 48d032035744 src/HOL/Divides.thy --- a/src/HOL/Divides.thy Thu Aug 18 09:29:11 2022 +0200 +++ b/src/HOL/Divides.thy Wed Aug 17 20:37:16 2022 +0000 @@ -11,6 +11,43 @@ subsection \More on division\ +subsubsection \Laws for div and mod with Unary Minus\ + +lemma zmod_zminus1_not_zero: + fixes k l :: int + shows "- k mod l \ 0 \ k mod l \ 0" + by (simp add: mod_eq_0_iff_dvd) + +lemma zmod_zminus2_not_zero: + fixes k l :: int + shows "k mod - l \ 0 \ k mod l \ 0" + by (simp add: mod_eq_0_iff_dvd) + +lemma zdiv_zminus1_eq_if: + \(- a) div b = (if a mod b = 0 then - (a div b) else - (a div b) - 1)\ + if \b \ 0\ for a b :: int + using that sgn_not_eq_imp [of b \- a\] + by (cases \a = 0\) (auto simp add: div_eq_div_abs [of \- a\ b] div_eq_div_abs [of a b] sgn_eq_0_iff) + +lemma zdiv_zminus2_eq_if: + \a div (- b) = (if a mod b = 0 then - (a div b) else - (a div b) - 1)\ + if \b \ 0\ for a b :: int + using that by (auto simp add: zdiv_zminus1_eq_if div_minus_right) + +lemma zmod_zminus1_eq_if: + \(- a) mod b = (if a mod b = 0 then 0 else b - (a mod b))\ + for a b :: int + by (cases \b = 0\) + (auto simp flip: minus_div_mult_eq_mod simp add: zdiv_zminus1_eq_if algebra_simps) + +lemma zmod_zminus2_eq_if: + \a mod (- b) = (if a mod b = 0 then 0 else (a mod b) - b)\ + for a b :: int + by (auto simp add: zmod_zminus1_eq_if mod_minus_right) + + +subsubsection \Monotonicity in the First Argument (Dividend)\ + inductive eucl_rel_int :: "int \ int \ int \ int \ bool" where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)" | eucl_rel_int_dividesI: "l \ 0 \ k = q * l \ eucl_rel_int k l (q, 0)" @@ -91,139 +128,20 @@ using unique_quotient [of k l] unique_remainder [of k l] by auto -lemma div_abs_eq_div_nat: - "\k\ div \l\ = int (nat \k\ div nat \l\)" - by (simp add: divide_int_def) - -lemma mod_abs_eq_div_nat: - "\k\ mod \l\ = int (nat \k\ mod nat \l\)" - by (simp add: modulo_int_def) - -lemma zdiv_int: - "int (a div b) = int a div int b" - by (simp add: divide_int_def) - -lemma zmod_int: - "int (a mod b) = int a mod int b" - by (simp add: modulo_int_def) - -lemma div_sgn_abs_cancel: - fixes k l v :: int - assumes "v \ 0" - shows "(sgn v * \k\) div (sgn v * \l\) = \k\ div \l\" -proof - - from assms have "sgn v = - 1 \ sgn v = 1" - by (cases "v \ 0") auto - then show ?thesis - using assms unfolding divide_int_def [of "sgn v * \k\" "sgn v * \l\"] - by (fastforce simp add: not_less div_abs_eq_div_nat) -qed - -lemma div_eq_sgn_abs: - fixes k l v :: int - assumes "sgn k = sgn l" - shows "k div l = \k\ div \l\" -proof (cases "l = 0") - case True - then show ?thesis - by simp -next - case False - with assms have "(sgn k * \k\) div (sgn l * \l\) = \k\ div \l\" - using div_sgn_abs_cancel [of l k l] by simp - then show ?thesis - by (simp add: sgn_mult_abs) -qed - -lemma div_dvd_sgn_abs: - fixes k l :: int - assumes "l dvd k" - shows "k div l = (sgn k * sgn l) * (\k\ div \l\)" -proof (cases "k = 0 \ l = 0") - case True - then show ?thesis - by auto -next - case False - then have "k \ 0" and "l \ 0" - by auto - show ?thesis - proof (cases "sgn l = sgn k") - case True - then show ?thesis - by (auto simp add: div_eq_sgn_abs) - next - case False - with \k \ 0\ \l \ 0\ - have "sgn l * sgn k = - 1" - by (simp add: sgn_if split: if_splits) - with assms show ?thesis - unfolding divide_int_def [of k l] - by (auto simp add: zdiv_int ac_simps) - qed -qed - -lemma div_noneq_sgn_abs: - fixes k l :: int - assumes "l \ 0" - assumes "sgn k \ sgn l" - shows "k div l = - (\k\ div \l\) - of_bool (\ l dvd k)" - using assms - by (simp only: divide_int_def [of k l], auto simp add: not_less zdiv_int) - - -subsubsection \Laws for div and mod with Unary Minus\ - lemma zminus1_lemma: "eucl_rel_int a b (q, r) ==> b \ 0 ==> eucl_rel_int (-a) b (if r=0 then -q else -q - 1, if r=0 then 0 else b-r)" by (force simp add: eucl_rel_int_iff right_diff_distrib) - -lemma zdiv_zminus1_eq_if: - "b \ (0::int) - \ (-a) div b = (if a mod b = 0 then - (a div b) else - (a div b) - 1)" -by (blast intro: eucl_rel_int [THEN zminus1_lemma, THEN div_int_unique]) - -lemma zmod_zminus1_eq_if: - "(-a::int) mod b = (if a mod b = 0 then 0 else b - (a mod b))" -proof (cases "b = 0") - case False - then show ?thesis - by (blast intro: eucl_rel_int [THEN zminus1_lemma, THEN mod_int_unique]) -qed auto - -lemma zmod_zminus1_not_zero: - fixes k l :: int - shows "- k mod l \ 0 \ k mod l \ 0" - by (simp add: mod_eq_0_iff_dvd) - -lemma zmod_zminus2_not_zero: - fixes k l :: int - shows "k mod - l \ 0 \ k mod l \ 0" - by (simp add: mod_eq_0_iff_dvd) - -lemma zdiv_zminus2_eq_if: - "b \ (0::int) - ==> a div (-b) = - (if a mod b = 0 then - (a div b) else - (a div b) - 1)" - by (auto simp add: zdiv_zminus1_eq_if div_minus_right) - -lemma zmod_zminus2_eq_if: - "a mod (-b::int) = (if a mod b = 0 then 0 else (a mod b) - b)" - by (auto simp add: zmod_zminus1_eq_if mod_minus_right) - - -subsubsection \Monotonicity in the First Argument (Dividend)\ - lemma zdiv_mono1: - fixes b::int - assumes "a \ a'" "0 < b" shows "a div b \ a' div b" + \a div b \ a' div b\ + if \a \ a'\ \0 < b\ + for a b b' :: int proof (rule unique_quotient_lemma) show "b * (a div b) + a mod b \ b * (a' div b) + a' mod b" - using assms(1) by auto -qed (use assms in auto) + using \a \ a'\ by auto +qed (use that in auto) lemma zdiv_mono1_neg: fixes b::int diff -r 77cbf472fcc9 -r 48d032035744 src/HOL/Euclidean_Division.thy --- a/src/HOL/Euclidean_Division.thy Thu Aug 18 09:29:11 2022 +0200 +++ b/src/HOL/Euclidean_Division.thy Wed Aug 17 20:37:16 2022 +0000 @@ -321,7 +321,7 @@ lemma div_plus_div_distrib_dvd_left: "c dvd a \ (a + b) div c = a div c + b div c" - by (cases "c = 0") (auto elim: dvdE) + by (cases "c = 0") auto lemma div_plus_div_distrib_dvd_right: "c dvd b \ (a + b) div c = a div c + b div c" @@ -603,7 +603,7 @@ subsection \Uniquely determined division\ - + class unique_euclidean_semiring = euclidean_semiring + assumes euclidean_size_mult: "euclidean_size (a * b) = euclidean_size a * euclidean_size b" fixes division_segment :: "'a \ 'a" @@ -1499,26 +1499,20 @@ instantiation int :: normalization_semidom begin -definition normalize_int :: "int \ int" - where [simp]: "normalize = (abs :: int \ int)" - -definition unit_factor_int :: "int \ int" - where [simp]: "unit_factor = (sgn :: int \ int)" +definition normalize_int :: \int \ int\ + where [simp]: \normalize = (abs :: int \ int)\ -definition divide_int :: "int \ int \ int" - where "k div l = (if l = 0 then 0 - else if sgn k = sgn l - then int (nat \k\ div nat \l\) - else - int (nat \k\ div nat \l\ + of_bool (\ l dvd k)))" +definition unit_factor_int :: \int \ int\ + where [simp]: \unit_factor = (sgn :: int \ int)\ + +definition divide_int :: \int \ int \ int\ + where \k div l = (sgn k * sgn l * int (nat \k\ div nat \l\) + - of_bool (l \ 0 \ sgn k \ sgn l \ \ l dvd k))\ lemma divide_int_unfold: - "(sgn k * int m) div (sgn l * int n) = - (if sgn l = 0 \ sgn k = 0 \ n = 0 then 0 - else if sgn k = sgn l - then int (m div n) - else - int (m div n + of_bool (\ n dvd m)))" - by (auto simp add: divide_int_def sgn_0_0 sgn_1_pos sgn_mult abs_mult - nat_mult_distrib) + \(sgn k * int m) div (sgn l * int n) = (sgn k * sgn l * int (m div n) + - of_bool ((k = 0 \ m = 0) \ l \ 0 \ n \ 0 \ sgn k \ sgn l \ \ n dvd m))\ + by (simp add: divide_int_def sgn_mult nat_mult_distrib abs_mult sgn_eq_0_iff ac_simps) instance proof fix k :: int show "k div 0 = 0" @@ -1537,6 +1531,21 @@ end +lemma div_abs_eq_div_nat: + "\k\ div \l\ = int (nat \k\ div nat \l\)" + by (auto simp add: divide_int_def) + +lemma div_eq_div_abs: + \k div l = sgn k * sgn l * (\k\ div \l\) + - of_bool (l \ 0 \ sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: divide_int_def [of k l] div_abs_eq_div_nat) + +lemma div_abs_eq: + \\k\ div \l\ = sgn k * sgn l * (k div l + of_bool (sgn k \ sgn l \ \ l dvd k))\ + for k l :: int + by (simp add: div_eq_div_abs [of k l] ac_simps) + lemma coprime_int_iff [simp]: "coprime (int m) (int n) \ coprime m n" (is "?P \ ?Q") proof @@ -1598,34 +1607,38 @@ instantiation int :: idom_modulo begin -definition modulo_int :: "int \ int \ int" - where "k mod l = (if l = 0 then k - else if sgn k = sgn l - then sgn l * int (nat \k\ mod nat \l\) - else sgn l * (\l\ * of_bool (\ l dvd k) - int (nat \k\ mod nat \l\)))" +definition modulo_int :: \int \ int \ int\ + where \k mod l = sgn k * int (nat \k\ mod nat \l\) + l * of_bool (sgn k \ sgn l \ \ l dvd k)\ lemma modulo_int_unfold: - "(sgn k * int m) mod (sgn l * int n) = - (if sgn l = 0 \ sgn k = 0 \ n = 0 then sgn k * int m - else if sgn k = sgn l - then sgn l * int (m mod n) - else sgn l * (int (n * of_bool (\ n dvd m)) - int (m mod n)))" - by (auto simp add: modulo_int_def sgn_0_0 sgn_1_pos sgn_mult abs_mult - nat_mult_distrib) + \(sgn k * int m) mod (sgn l * int n) = + sgn k * int (m mod (of_bool (l \ 0) * n)) + (sgn l * int n) * of_bool ((k = 0 \ m = 0) \ sgn k \ sgn l \ \ n dvd m)\ + by (auto simp add: modulo_int_def sgn_mult abs_mult) instance proof fix k l :: int obtain n m and s t where "k = sgn s * int n" and "l = sgn t * int m" by (blast intro: int_sgnE elim: that) then show "k div l * l + k mod l = k" - by (auto simp add: divide_int_unfold modulo_int_unfold algebra_simps dest!: sgn_not_eq_imp) - (simp_all add: of_nat_mult [symmetric] of_nat_add [symmetric] - distrib_left [symmetric] minus_mult_right - del: of_nat_mult minus_mult_right [symmetric]) + by (simp add: divide_int_unfold modulo_int_unfold algebra_simps modulo_nat_def of_nat_diff) qed end +lemma mod_abs_eq_div_nat: + "\k\ mod \l\ = int (nat \k\ mod nat \l\)" + by (simp add: modulo_int_def) + +lemma mod_eq_mod_abs: + \k mod l = sgn k * (\k\ mod \l\) + l * of_bool (sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: modulo_int_def [of k l] mod_abs_eq_div_nat) + +lemma mod_abs_eq: + \\k\ mod \l\ = sgn k * (k mod l - l * of_bool (sgn k \ sgn l \ \ l dvd k))\ + for k l :: int + by (auto simp: mod_eq_mod_abs [of k l]) + instantiation int :: unique_euclidean_ring begin @@ -1649,8 +1662,9 @@ obtain n m and s t where "k = sgn s * int n" and "l = sgn t * int m" by (blast intro: int_sgnE elim: that) with that show ?thesis - by (simp add: modulo_int_unfold sgn_0_0 sgn_1_pos sgn_1_neg - abs_mult mod_greater_zero_iff_not_dvd) + by (auto simp add: modulo_int_unfold abs_mult mod_greater_zero_iff_not_dvd + simp flip: right_diff_distrib dest!: sgn_not_eq_imp) + (simp add: sgn_0_0) qed lemma sgn_mod: @@ -1659,8 +1673,8 @@ obtain n m and s t where "k = sgn s * int n" and "l = sgn t * int m" by (blast intro: int_sgnE elim: that) with that show ?thesis - by (simp add: modulo_int_unfold sgn_0_0 sgn_1_pos sgn_1_neg sgn_mult) - (simp add: dvd_eq_mod_eq_0) + by (auto simp add: modulo_int_unfold sgn_mult mod_greater_zero_iff_not_dvd + simp flip: right_diff_distrib dest!: sgn_not_eq_imp) qed instance proof @@ -1700,8 +1714,8 @@ from \r = 0\ have *: "q * l + r = sgn (t * s) * int (n * m)" using q l by (simp add: ac_simps sgn_mult) from \s \ 0\ \n > 0\ show ?thesis - by (simp only: *, simp only: q l divide_int_unfold) - (auto simp add: sgn_mult sgn_0_0 sgn_1_pos) + by (simp only: *, simp only: * q l divide_int_unfold) + (auto simp add: sgn_mult ac_simps) qed next case False @@ -1728,6 +1742,12 @@ end +lemma div_sgn_abs_cancel: + fixes k l v :: int + assumes "v \ 0" + shows "(sgn v * \k\) div (sgn v * \l\) = \k\ div \l\" + using assms by (simp add: sgn_mult abs_mult sgn_0_0 of_nat_div divide_int_def [of "sgn v * \k\" "sgn v * \l\"]) + lemma pos_mod_bound [simp]: "k mod l < l" if "l > 0" for k l :: int proof - @@ -1739,7 +1759,7 @@ by simp ultimately show ?thesis by (simp only: modulo_int_unfold) - (simp add: mod_greater_zero_iff_not_dvd) + (auto simp add: mod_greater_zero_iff_not_dvd sgn_1_pos) qed lemma neg_mod_bound [simp]: @@ -1754,7 +1774,7 @@ by simp ultimately show ?thesis by (simp only: modulo_int_unfold) - (simp add: mod_greater_zero_iff_not_dvd) + (auto simp add: mod_greater_zero_iff_not_dvd sgn_1_neg) qed lemma pos_mod_sign [simp]: @@ -1767,7 +1787,7 @@ moreover from this that have "n > 0" by simp ultimately show ?thesis - by (simp only: modulo_int_unfold) simp + by (simp only: modulo_int_unfold) (auto simp add: sgn_1_pos) qed lemma neg_mod_sign [simp]: @@ -1780,8 +1800,12 @@ moreover define n where "n = Suc q" then have "Suc q = n" by simp + moreover have \int (m mod n) \ int n\ + using \Suc q = n\ by simp + then have \sgn s * int (m mod n) \ int n\ + by (cases s \0::int\ rule: linorder_cases) simp_all ultimately show ?thesis - by (simp only: modulo_int_unfold) simp + by (simp only: modulo_int_unfold) auto qed lemma div_pos_pos_trivial [simp]: @@ -2075,7 +2099,7 @@ proof (cases \n \ m\) case True then show ?thesis - by (simp add: Suc_le_lessD min.absorb2) + by (simp add: Suc_le_lessD) next case False then have \m < n\ @@ -2109,7 +2133,27 @@ by standard (simp_all add: dvd_eq_mod_eq_0) instance int :: unique_euclidean_ring_with_nat - by standard (simp_all add: dvd_eq_mod_eq_0 divide_int_def division_segment_int_def) + by standard (auto simp add: divide_int_def division_segment_int_def elim: contrapos_np) + +lemma div_eq_sgn_abs: + fixes k l v :: int + assumes "sgn k = sgn l" + shows "k div l = \k\ div \l\" + using assms by (auto simp add: divide_int_def [of k l] of_nat_div) + +lemma div_dvd_sgn_abs: + fixes k l :: int + assumes "l dvd k" + shows "k div l = (sgn k * sgn l) * (\k\ div \l\)" + using assms by (auto simp add: divide_int_def [of k l] of_nat_div) + +lemma div_noneq_sgn_abs: + fixes k l :: int + assumes "l \ 0" + assumes "sgn k \ sgn l" + shows "k div l = - (\k\ div \l\) - of_bool (\ l dvd k)" + using assms + by (simp only: divide_int_def [of k l]) (auto simp add: of_nat_div sgn_0_0 dest!: sgn_not_eq_imp) lemma zdiv_zmult2_eq: \a div (b * c) = (a div b) div c\ if \c \ 0\ for a b c :: int @@ -2135,6 +2179,14 @@ using mod_mult2_eq' [of \- a\ \nat (- b)\ \nat c\] by simp qed +lemma zdiv_int: + "int (a div b) = int a div int b" + by (fact of_nat_div) + +lemma zmod_int: + "int (a mod b) = int a mod int b" + by (fact of_nat_mod) + subsection \Code generation\ diff -r 77cbf472fcc9 -r 48d032035744 src/HOL/Library/Signed_Division.thy --- a/src/HOL/Library/Signed_Division.thy Thu Aug 18 09:29:11 2022 +0200 +++ b/src/HOL/Library/Signed_Division.thy Wed Aug 17 20:37:16 2022 +0000 @@ -7,9 +7,58 @@ imports Main begin -class signed_division = - fixes signed_divide :: \'a \ 'a \ 'a\ (infixl "sdiv" 70) - and signed_modulo :: \'a \ 'a \ 'a\ (infixl "smod" 70) +lemma sgn_div_eq_sgn_mult: + \sgn (a div b) = sgn (a * b)\ + if \a div b \ 0\ for a b :: int +proof - + have \0 \ \a\ div \b\\ + by (cases \b = 0\) (simp_all add: pos_imp_zdiv_nonneg_iff) + then have \\a\ div \b\ \ 0 \ 0 < \a\ div \b\\ + by (simp add: less_le) + also have \\ \ \a\ \ \b\\ + using that nonneg1_imp_zdiv_pos_iff by auto + finally have *: \\a\ div \b\ \ 0 \ \b\ \ \a\\ . + show ?thesis + using \0 \ \a\ div \b\\ that + by (auto simp add: div_eq_div_abs [of a b] div_eq_sgn_abs [of a b] + sgn_mult sgn_1_pos sgn_1_neg sgn_eq_0_iff nonneg1_imp_zdiv_pos_iff * dest: sgn_not_eq_imp) +qed + +class signed_division = comm_semiring_1_cancel + + fixes signed_divide :: \'a \ 'a \ 'a\ (infixl \sdiv\ 70) + and signed_modulo :: \'a \ 'a \ 'a\ (infixl \smod\ 70) + assumes sdiv_mult_smod_eq: \a sdiv b * b + a smod b = a\ +begin + +lemma mult_sdiv_smod_eq: + \b * (a sdiv b) + a smod b = a\ + using sdiv_mult_smod_eq [of a b] by (simp add: ac_simps) + +lemma smod_sdiv_mult_eq: + \a smod b + a sdiv b * b = a\ + using sdiv_mult_smod_eq [of a b] by (simp add: ac_simps) + +lemma smod_mult_sdiv_eq: + \a smod b + b * (a sdiv b) = a\ + using sdiv_mult_smod_eq [of a b] by (simp add: ac_simps) + +lemma minus_sdiv_mult_eq_smod: + \a - a sdiv b * b = a smod b\ + by (rule add_implies_diff [symmetric]) (fact smod_sdiv_mult_eq) + +lemma minus_mult_sdiv_eq_smod: + \a - b * (a sdiv b) = a smod b\ + by (rule add_implies_diff [symmetric]) (fact smod_mult_sdiv_eq) + +lemma minus_smod_eq_sdiv_mult: + \a - a smod b = a sdiv b * b\ + by (rule add_implies_diff [symmetric]) (fact sdiv_mult_smod_eq) + +lemma minus_smod_eq_mult_sdiv: + \a - a smod b = b * (a sdiv b)\ + by (rule add_implies_diff [symmetric]) (fact mult_sdiv_smod_eq) + +end instantiation int :: signed_division begin @@ -18,12 +67,45 @@ where \k sdiv l = sgn k * sgn l * (\k\ div \l\)\ for k l :: int definition signed_modulo_int :: \int \ int \ int\ - where \k smod l = k - (k sdiv l) * l\ for k l :: int + where \k smod l = sgn k * (\k\ mod \l\)\ for k l :: int -instance .. +instance by standard + (simp add: signed_divide_int_def signed_modulo_int_def div_abs_eq mod_abs_eq algebra_simps) end +lemma divide_int_eq_signed_divide_int: + \k div l = k sdiv l - of_bool (l \ 0 \ sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: div_eq_div_abs [of k l] signed_divide_int_def) + +lemma signed_divide_int_eq_divide_int: + \k sdiv l = k div l + of_bool (l \ 0 \ sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: divide_int_eq_signed_divide_int) + +lemma modulo_int_eq_signed_modulo_int: + \k mod l = k smod l + l * of_bool (sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: mod_eq_mod_abs [of k l] signed_modulo_int_def) + +lemma signed_modulo_int_eq_modulo_int: + \k smod l = k mod l - l * of_bool (sgn k \ sgn l \ \ l dvd k)\ + for k l :: int + by (simp add: modulo_int_eq_signed_modulo_int) + +lemma sdiv_int_div_0: + "(x :: int) sdiv 0 = 0" + by (clarsimp simp: signed_divide_int_def) + +lemma sdiv_int_0_div [simp]: + "0 sdiv (x :: int) = 0" + by (clarsimp simp: signed_divide_int_def) + +lemma smod_int_alt_def: + "(a::int) smod b = sgn (a) * (abs a mod abs b)" + by (fact signed_modulo_int_def) + lemma int_sdiv_simps [simp]: "(a :: int) sdiv 1 = a" "(a :: int) sdiv 0 = 0" @@ -31,11 +113,13 @@ apply (auto simp: signed_divide_int_def sgn_if) done -lemma sgn_div_eq_sgn_mult: - "a div b \ 0 \ sgn ((a :: int) div b) = sgn (a * b)" - apply (clarsimp simp: sgn_if zero_le_mult_iff neg_imp_zdiv_nonneg_iff not_less) - apply (metis less_le mult_le_0_iff neg_imp_zdiv_neg_iff not_less pos_imp_zdiv_neg_iff zdiv_eq_0_iff) - done +lemma smod_int_mod_0 [simp]: + "x smod (0 :: int) = x" + by (clarsimp simp: signed_modulo_int_def abs_mult_sgn ac_simps) + +lemma smod_int_0_mod [simp]: + "0 smod (x :: int) = 0" + by (clarsimp simp: smod_int_alt_def) lemma sgn_sdiv_eq_sgn_mult: "a sdiv b \ 0 \ sgn ((a :: int) sdiv b) = sgn (a * b)" @@ -71,38 +155,17 @@ done lemma sdiv_int_range: - "(a :: int) sdiv b \ { - (abs a) .. (abs a) }" - apply (unfold signed_divide_int_def) - apply (subgoal_tac "(abs a) div (abs b) \ (abs a)") - apply (auto simp add: sgn_if not_less) - apply (metis le_less le_less_trans neg_equal_0_iff_equal neg_less_iff_less not_le pos_imp_zdiv_neg_iff) - apply (metis add.inverse_neutral div_int_pos_iff le_less neg_le_iff_le order_trans) - apply (metis div_minus_right le_less_trans neg_imp_zdiv_neg_iff neg_less_0_iff_less not_le) - using div_int_pos_iff apply fastforce - apply (auto simp add: abs_if not_less) - apply (metis add.inverse_inverse add_0_left div_by_1 div_minus_right less_le neg_0_le_iff_le not_le not_one_le_zero zdiv_mono2 zless_imp_add1_zle) - apply (metis div_by_1 neg_0_less_iff_less pos_imp_zdiv_pos_iff zdiv_mono2 zero_less_one) - apply (metis add.inverse_neutral div_by_0 div_by_1 int_div_less_self int_one_le_iff_zero_less less_le less_minus_iff order_refl) - apply (metis div_by_1 divide_int_def int_div_less_self less_le linorder_neqE_linordered_idom order_refl unique_euclidean_semiring_numeral_class.div_less) - done - -lemma sdiv_int_div_0 [simp]: - "(x :: int) sdiv 0 = 0" - by (clarsimp simp: signed_divide_int_def) - -lemma sdiv_int_0_div [simp]: - "0 sdiv (x :: int) = 0" - by (clarsimp simp: signed_divide_int_def) - -lemma smod_int_alt_def: - "(a::int) smod b = sgn (a) * (abs a mod abs b)" - apply (clarsimp simp: signed_modulo_int_def signed_divide_int_def) - apply (clarsimp simp: minus_div_mult_eq_mod [symmetric] abs_sgn sgn_mult sgn_if algebra_split_simps) - done + \a sdiv b \ {- \a\..\a\}\ for a b :: int + using zdiv_mono2 [of \\a\\ 1 \\b\\] + by (cases \b = 0\; cases \sgn b = sgn a\) + (auto simp add: signed_divide_int_def pos_imp_zdiv_nonneg_iff + dest!: sgn_not_eq_imp intro: order_trans [of _ 0]) lemma smod_int_range: - "b \ 0 \ (a::int) smod b \ { - abs b + 1 .. abs b - 1 }" - apply (case_tac "b > 0") + \a smod b \ {- \b\ + 1..\b\ - 1}\ + if \b \ 0\ for a b :: int + using that + apply (cases \b > 0\) apply (insert pos_mod_conj [where a=a and b=b])[1] apply (insert pos_mod_conj [where a="-a" and b=b])[1] apply (auto simp: smod_int_alt_def algebra_simps sgn_if @@ -129,14 +192,6 @@ apply (auto simp: add1_zle_eq smod_int_alt_def sgn_if) done -lemma smod_int_mod_0 [simp]: - "x smod (0 :: int) = x" - by (clarsimp simp: signed_modulo_int_def) - -lemma smod_int_0_mod [simp]: - "0 smod (x :: int) = 0" - by (clarsimp simp: smod_int_alt_def) - lemma smod_mod_positive: "\ 0 \ (a :: int); 0 \ b \ \ a smod b = a mod b" by (clarsimp simp: smod_int_alt_def zsgn_def) diff -r 77cbf472fcc9 -r 48d032035744 src/HOL/Rings.thy --- a/src/HOL/Rings.thy Thu Aug 18 09:29:11 2022 +0200 +++ b/src/HOL/Rings.thy Wed Aug 17 20:37:16 2022 +0000 @@ -2567,6 +2567,10 @@ "sgn a * sgn a = of_bool (a \ 0)" by (cases "a > 0") simp_all +lemma left_sgn_mult_self_eq [simp]: + \sgn a * (sgn a * b) = of_bool (a \ 0) * b\ + by (simp flip: mult.assoc) + lemma abs_mult_self_eq [simp]: "\a\ * \a\ = a * a" by (cases "a > 0") simp_all