From 1e96908f8705844918010931b477363aaba66489 Mon Sep 17 00:00:00 2001 From: Aolin Date: Thu, 26 Dec 2024 19:17:44 +0800 Subject: [PATCH] blog: add "Avoid Negative Division Pitfalls in Python" add rehype-katex and remark-math --- ...id-negative-division-pitfalls-in-python.md | 168 ++++++++++++++++++ .../docs/python/python-negative-division.md | 165 +++++++++++++++++ website/docusaurus.config.js | 13 ++ website/package.json | 4 +- website/sidebars.js | 1 + website/yarn.lock | 151 ++++++++++++++++ 6 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 website/blog/2024-12-26-avoid-negative-division-pitfalls-in-python.md create mode 100644 website/docs/python/python-negative-division.md diff --git a/website/blog/2024-12-26-avoid-negative-division-pitfalls-in-python.md b/website/blog/2024-12-26-avoid-negative-division-pitfalls-in-python.md new file mode 100644 index 0000000..001935f --- /dev/null +++ b/website/blog/2024-12-26-avoid-negative-division-pitfalls-in-python.md @@ -0,0 +1,168 @@ +--- +slug: 2024-12-26-avoid-negative-division-pitfalls-in-python +title: "Avoid Negative Division Pitfalls in Python" +authors: [Oreo] +tags: [Python, Tips & Tricks] +--- + +```mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +``` + +While working on automated accounting transactions with [Beancount](https://github.com/beancount/beancount), I ran into an unexpected issue involving floating-point number conversions. In financial calculations, it's common practice to convert floating-point values to integers (for example, converting 1.55 to 155) by multiplying by 100, perform the necessary calculations, and then convert the result back by dividing by 100. This method helps maintain precision when dealing with currency values. + +Sounds straightforward, doesn't it? That's what I thought until negative numbers entered the equation. + +To my surprise, when I attempted to convert -155 back to -1.55, Python returned **-2.45** instead. Let's dive into why this happens. + + + +### The unexpected behavior + +Here's the Python function where the issue occurs: + +```python +def int_to_float(value: int, decimal: int): + exp = 1 + for _ in range(decimal): + exp = exp * 10 + return f"{value // exp:,}.{str(value % exp).zfill(decimal)}" + +print(int_to_float(100, 2)) # 1.00 +print(int_to_float(-100, 2)) # -1.00 +print(int_to_float(155, 2)) # 1.55 +print(int_to_float(-155, 2)) # -2.45 # Oops! +``` + + + + +As you can see, when the input is `-155`, the function returns `-2.45` instead of the expected `-1.55`. This happens because Python handles integer division and modulo operations in a way that might not match our intuitive expectations. Here's what's happening behind the scenes: + +- `-155 // 100` results in `-2` (integer division) +- `-155 % 100` results in `45` (modulo) + +This behavior is explained in the [Python FAQ: Why does `-22 // 10` return -3?](https://docs.python.org/3/faq/programming.html#why-does-22-10-return-3) + +## The math behind the mystery + +[Wikipedia: Modulo](https://en.wikipedia.org/wiki/Modulo) provides helpful insights into how different programming languages implement modulo operations. + +Python uses floored division for its `%` operator, which is defined as: + +$$ +q = \left\lfloor \frac{a}{n} \right\rfloor, r = a - n\left\lfloor \frac{a}{n} \right\rfloor +$$ + +Under this implementation, the remainder `r` always shares the same sign as the divisor `n`. + +For examples: + +```python +print(10 % 3) # 1 +print(-10 % 3) # 2 +print(-10 % -3) # -1 +print(10 % -3) # -2 +``` + + + + +In contrast, Bash, C++ `%`, and Python's `math.fmod()` use truncated division: + +$$ +q = \operatorname{trunc}\left(\frac{a}{n}\right), r = a - n\operatorname{trunc}\left(\frac{a}{n}\right) +$$ + +With truncated division, the remainder `r` shares the same sign as the dividend `a`. + +For examples: + + + + + ```shell-session + echo "10 % 3 =" $((10 % 3)) # 1 + echo "-10 % 3 =" $((-10 % 3)) # -1 + echo "-10 % -3 =" $((-10 % -3)) # -1 + echo "10 % -3 =" $((10 % -3)) # 1 + ``` + + + + + + + + + ```cpp + #include + + int main() { + std::cout << "10 % 3 = " << (10 % 3) << '\n'; // 1 + std::cout << "-10 % 3 = " << (-10 % 3) << '\n'; // -1 + std::cout << "-10 % -3 = " << (-10 % -3) << '\n'; // -1 + std::cout << "10 % -3 = " << (10 % -3) << '\n'; // 1 + return 0; + } + ``` + + + + + + + + + ```python + from math import fmod + + print(f"10 % 3 = {fmod(10, 3)}") # 1.0 + print(f"-10 % 3 = {fmod(-10, 3)}") # -1.0 + print(f"-10 % -3 = {fmod(-10, -3)}") # -1.0 + print(f"10 % -3 = {fmod(10, -3)}") # 1.0 + ``` + + + + + + + +## The solution + +The following is an updated version of the function that correctly handles negative numbers: + +```python +def int_to_float(value: int, decimal: int): + exp = 1 + for _ in range(decimal): + exp = exp * 10 + if value < 0: + value = -value + sign = "-" + else: + sign = "" + ret = f"{sign}{value // exp:,}.{str(value % exp).zfill(decimal)}" + return ret + +print(int_to_float(100, 2)) # 1.00 +print(int_to_float(-100, 2)) # -1.00 +print(int_to_float(155, 2)) # 1.55 +print(int_to_float(-155, 2)) # -1.55 +``` + + + + +This solution handles negative numbers by separating the sign from the absolute value and performing division and modulo operations on the absolute value, ensuring correct results for both positive and negative numbers. Now, `int_to_float(-155, 2)` correctly returns `-1.55` instead of `-2.45`. + +## What I learned + +~~Avoid using negative division~~ + +The main takeaway here is simple: **be cautious when working with negative division** in programming. + +- Understand how your programming language handles division and modulo operations. +- Write comprehensive tests that cover edge cases, especially with negative numbers. diff --git a/website/docs/python/python-negative-division.md b/website/docs/python/python-negative-division.md new file mode 100644 index 0000000..ebd4ff8 --- /dev/null +++ b/website/docs/python/python-negative-division.md @@ -0,0 +1,165 @@ +--- +sidebar_label: "Negative Division" +title: "Negative Division Pitfalls in Python" +description: "The unexpected behavior of negative division in Python and how to handle it as expected." +--- + +```mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +``` + +While working on automated accounting transactions with [Beancount](https://github.com/beancount/beancount), I ran into an unexpected issue involving floating-point number conversions. In financial calculations, it's common practice to convert floating-point values to integers (for example, converting 1.55 to 155) by multiplying by 100, perform the necessary calculations, and then convert the result back by dividing by 100. This method helps maintain precision when dealing with currency values. + +Sounds straightforward, doesn't it? That's what I thought until negative numbers entered the equation. + +To my surprise, when I attempted to convert -155 back to -1.55, Python returned **-2.45** instead. Let's dive into why this happens. + +### The unexpected behavior + +Here's the Python function where the issue occurs: + +```python +def int_to_float(value: int, decimal: int): + exp = 1 + for _ in range(decimal): + exp = exp * 10 + return f"{value // exp:,}.{str(value % exp).zfill(decimal)}" + +print(int_to_float(100, 2)) # 1.00 +print(int_to_float(-100, 2)) # -1.00 +print(int_to_float(155, 2)) # 1.55 +print(int_to_float(-155, 2)) # -2.45 # Oops! +``` + + + + +As you can see, when the input is `-155`, the function returns `-2.45` instead of the expected `-1.55`. This happens because Python handles integer division and modulo operations in a way that might not match our intuitive expectations. Here's what's happening behind the scenes: + +- `-155 // 100` results in `-2` (integer division) +- `-155 % 100` results in `45` (modulo) + +This behavior is explained in the [Python FAQ: Why does `-22 // 10` return -3?](https://docs.python.org/3/faq/programming.html#why-does-22-10-return-3) + +## The math behind the mystery + +[Wikipedia: Modulo](https://en.wikipedia.org/wiki/Modulo) provides helpful insights into how different programming languages implement modulo operations. + +Python uses floored division for its `%` operator, which is defined as: + +$$ +q = \left\lfloor \frac{a}{n} \right\rfloor, r = a - n\left\lfloor \frac{a}{n} \right\rfloor +$$ + +Under this implementation, the remainder `r` always shares the same sign as the divisor `n`. + +For examples: + +```python +print(10 % 3) # 1 +print(-10 % 3) # 2 +print(-10 % -3) # -1 +print(10 % -3) # -2 +``` + + + + +In contrast, Bash, C++ `%`, and Python's `math.fmod()` use truncated division: + +$$ +q = \operatorname{trunc}\left(\frac{a}{n}\right), r = a - n\operatorname{trunc}\left(\frac{a}{n}\right) +$$ + +With truncated division, the remainder `r` shares the same sign as the dividend `a`. + +For examples: + + + + + ```shell-session + echo "10 % 3 =" $((10 % 3)) # 1 + echo "-10 % 3 =" $((-10 % 3)) # -1 + echo "-10 % -3 =" $((-10 % -3)) # -1 + echo "10 % -3 =" $((10 % -3)) # 1 + ``` + + + + + + + + + ```cpp + #include + + int main() { + std::cout << "10 % 3 = " << (10 % 3) << '\n'; // 1 + std::cout << "-10 % 3 = " << (-10 % 3) << '\n'; // -1 + std::cout << "-10 % -3 = " << (-10 % -3) << '\n'; // -1 + std::cout << "10 % -3 = " << (10 % -3) << '\n'; // 1 + return 0; + } + ``` + + + + + + + + + ```python + from math import fmod + + print(f"10 % 3 = {fmod(10, 3)}") # 1.0 + print(f"-10 % 3 = {fmod(-10, 3)}") # -1.0 + print(f"-10 % -3 = {fmod(-10, -3)}") # -1.0 + print(f"10 % -3 = {fmod(10, -3)}") # 1.0 + ``` + + + + + + + +## The solution + +The following is an updated version of the function that correctly handles negative numbers: + +```python +def int_to_float(value: int, decimal: int): + exp = 1 + for _ in range(decimal): + exp = exp * 10 + if value < 0: + value = -value + sign = "-" + else: + sign = "" + ret = f"{sign}{value // exp:,}.{str(value % exp).zfill(decimal)}" + return ret + +print(int_to_float(100, 2)) # 1.00 +print(int_to_float(-100, 2)) # -1.00 +print(int_to_float(155, 2)) # 1.55 +print(int_to_float(-155, 2)) # -1.55 +``` + + + + +This solution handles negative numbers by separating the sign from the absolute value and performing division and modulo operations on the absolute value, ensuring correct results for both positive and negative numbers. Now, `int_to_float(-155, 2)` correctly returns `-1.55` instead of `-2.45`. + +## What I learned + +~~Avoid using negative division~~ + +The main takeaway here is simple: **be cautious when working with negative division** in programming. + +- Understand how your programming language handles division and modulo operations. +- Write comprehensive tests that cover edge cases, especially with negative numbers. diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 31788f8..b0b6ae7 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -2,6 +2,8 @@ // Note: type annotations allow type checking and IDEs autocompletion import {themes as prismThemes} from 'prism-react-renderer'; +import remarkMath from 'remark-math'; +import rehypeKatex from 'rehype-katex'; /** @type {import('@docusaurus/types').Config} */ export default { @@ -20,6 +22,13 @@ export default { { href: "https://unpkg.com/@antonz/codapi@0.19.7/dist/snippet.css", }, + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: + 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', + }, ], scripts: [ { @@ -70,6 +79,8 @@ export default { // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/Oreoxmt/oreo.life-v2', + remarkPlugins: [remarkMath], + rehypePlugins: [rehypeKatex], }, blog: { blogTitle: "Oreo's blog", @@ -77,6 +88,8 @@ export default { blogSidebarTitle: 'All posts', blogSidebarCount: 'ALL', showReadingTime: true, + remarkPlugins: [remarkMath], + rehypePlugins: [rehypeKatex], feedOptions: { xslt: true, type: 'all', diff --git a/website/package.json b/website/package.json index c7c7d72..509ee7e 100644 --- a/website/package.json +++ b/website/package.json @@ -24,7 +24,9 @@ "prism-react-renderer": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-player": "^2.16.0" + "react-player": "^2.16.0", + "rehype-katex": "7", + "remark-math": "6" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.6.3", diff --git a/website/sidebars.js b/website/sidebars.js index 6060ed7..31f8acf 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -66,6 +66,7 @@ const sidebars = { }, items: [ 'python/time-in-python', + 'python/python-negative-division', 'python/python-iterator', 'how-tos/python-test-shell-scripts', 'how-tos/manage-python-project-using-poetry', diff --git a/website/yarn.lock b/website/yarn.lock index 2266fa5..2fb17f3 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -3580,6 +3580,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== +"@types/katex@^0.16.0": + version "0.16.7" + resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.16.7.tgz#03ab680ab4fa4fbc6cb46ecf987ecad5d8019868" + integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ== + "@types/mdast@^4.0.0", "@types/mdast@^4.0.2": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" @@ -5896,6 +5901,37 @@ hasown@^2.0.0, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +hast-util-from-dom@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz#c3c92fbd8d4e1c1625edeb3a773952b9e4ad64a8" + integrity sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q== + dependencies: + "@types/hast" "^3.0.0" + hastscript "^9.0.0" + web-namespaces "^2.0.0" + +hast-util-from-html-isomorphic@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz#b31baee386a899a2472326a3c5692f29f86d1d3c" + integrity sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw== + dependencies: + "@types/hast" "^3.0.0" + hast-util-from-dom "^5.0.0" + hast-util-from-html "^2.0.0" + unist-util-remove-position "^5.0.0" + +hast-util-from-html@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz#485c74785358beb80c4ba6346299311ac4c49c82" + integrity sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.1.0" + hast-util-from-parse5 "^8.0.0" + parse5 "^7.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + hast-util-from-parse5@^8.0.0: version "8.0.1" resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz#654a5676a41211e14ee80d1b1758c399a0327651" @@ -5910,6 +5946,13 @@ hast-util-from-parse5@^8.0.0: vfile-location "^5.0.0" web-namespaces "^2.0.0" +hast-util-is-element@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz#6e31a6532c217e5b533848c7e52c9d9369ca0932" + integrity sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g== + dependencies: + "@types/hast" "^3.0.0" + hast-util-parse-selector@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" @@ -5992,6 +6035,16 @@ hast-util-to-parse5@^8.0.0: web-namespaces "^2.0.0" zwitch "^2.0.0" +hast-util-to-text@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz#57b676931e71bf9cb852453678495b3080bfae3e" + integrity sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + hast-util-is-element "^3.0.0" + unist-util-find-after "^5.0.0" + hast-util-whitespace@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" @@ -6010,6 +6063,17 @@ hastscript@^8.0.0: property-information "^6.0.0" space-separated-tokens "^2.0.0" +hastscript@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-9.0.0.tgz#2b76b9aa3cba8bf6d5280869f6f6f7165c230763" + integrity sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^4.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -6613,6 +6677,13 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +katex@^0.16.0: + version "0.16.18" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.18.tgz#20781284288bc52805c519e48ac756163ad4b1f3" + integrity sha512-LRuk0rPdXrecAFwQucYjMiIs0JFefk6N1q/04mlw14aVIVgxq1FO0MA9RiIIGVaKOB5GIP5GH4aBBNraZERmaQ== + dependencies: + commander "^8.3.0" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -6961,6 +7032,19 @@ mdast-util-gfm@^3.0.0: mdast-util-gfm-task-list-item "^2.0.0" mdast-util-to-markdown "^2.0.0" +mdast-util-math@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-math/-/mdast-util-math-3.0.0.tgz#8d79dd3baf8ab8ac781f62b8853768190b9a00b0" + integrity sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + longest-streak "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.1.0" + unist-util-remove-position "^5.0.0" + mdast-util-mdx-expression@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" @@ -7051,6 +7135,21 @@ mdast-util-to-markdown@^2.0.0: unist-util-visit "^5.0.0" zwitch "^2.0.0" +mdast-util-to-markdown@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + mdast-util-to-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" @@ -7229,6 +7328,19 @@ micromark-extension-gfm@^3.0.0: micromark-util-combine-extensions "^2.0.0" micromark-util-types "^2.0.0" +micromark-extension-math@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz#c42ee3b1dd5a9a03584e83dd8f08e3de510212c1" + integrity sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg== + dependencies: + "@types/katex" "^0.16.0" + devlop "^1.0.0" + katex "^0.16.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-mdx-expression@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz#1407b9ce69916cf5e03a196ad9586889df25302a" @@ -9003,6 +9115,19 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" +rehype-katex@7: + version "7.0.1" + resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-7.0.1.tgz#832e6d7af2744a228981d1b0fe89483a9e7c93a1" + integrity sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA== + dependencies: + "@types/hast" "^3.0.0" + "@types/katex" "^0.16.0" + hast-util-from-html-isomorphic "^2.0.0" + hast-util-to-text "^4.0.0" + katex "^0.16.0" + unist-util-visit-parents "^6.0.0" + vfile "^6.0.0" + rehype-raw@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4" @@ -9060,6 +9185,16 @@ remark-gfm@^4.0.0: remark-stringify "^11.0.0" unified "^11.0.0" +remark-math@6: + version "6.0.0" + resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-6.0.0.tgz#0acdf74675f1c195fea6efffa78582f7ed7fc0d7" + integrity sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-math "^3.0.0" + micromark-extension-math "^3.0.0" + unified "^11.0.0" + remark-mdx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-3.0.1.tgz#8f73dd635c1874e44426e243f72c0977cf60e212" @@ -9900,6 +10035,14 @@ unique-string@^3.0.0: dependencies: crypto-random-string "^4.0.0" +unist-util-find-after@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz#3fccc1b086b56f34c8b798e1ff90b5c54468e896" + integrity sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-is@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" @@ -9921,6 +10064,14 @@ unist-util-position@^5.0.0: dependencies: "@types/unist" "^3.0.0" +unist-util-remove-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" + integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== + dependencies: + "@types/unist" "^3.0.0" + unist-util-visit "^5.0.0" + unist-util-stringify-position@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2"