{"id":19730567,"url":"https://github.com/begriffs/pg_rational","last_synced_at":"2025-02-27T20:22:33.665Z","repository":{"id":38008262,"uuid":"121482121","full_name":"begriffs/pg_rational","owner":"begriffs","description":"Precise fractional arithmetic for PostgreSQL","archived":false,"fork":false,"pushed_at":"2023-03-15T09:47:12.000Z","size":65,"stargazers_count":241,"open_issues_count":6,"forks_count":14,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-10T17:50:16.701Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PLpgSQL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/begriffs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-14T07:16:52.000Z","updated_at":"2024-12-31T13:53:29.000Z","dependencies_parsed_at":"2025-01-10T17:42:54.237Z","dependency_job_id":"9a64419b-10e5-48fd-bf4f-7e48de7d6e2d","html_url":"https://github.com/begriffs/pg_rational","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/begriffs%2Fpg_rational","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/begriffs%2Fpg_rational/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/begriffs%2Fpg_rational/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/begriffs%2Fpg_rational/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/begriffs","download_url":"https://codeload.github.com/begriffs/pg_rational/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241055947,"owners_count":19901688,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T00:16:49.793Z","updated_at":"2025-02-27T20:22:33.643Z","avatar_url":"https://github.com/begriffs.png","language":"PLpgSQL","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Precise fractions for PostgreSQL\n\nAn efficient custom type. Perfect for exact arithmetic or user-specified\ntable row ordering. Holds values as big as an integer, with matching\nprecision in the denominator.\n\n### Features\n\n* Stores fractions in exactly 64 bits (same size as float)\n* Written in C for high performance\n* Detects and halts arithmetic overflow for correctness\n* Uses native CPU instructions for fast overflow detection\n* Defers GCD calculation until requested or absolutely required\n* Supports btree and hash indices\n* Implements Stern-Brocot trees for finding intermediate points\n* Coercion from integer/bigint/tuple\n* Custom aggregate\n\n### Motivation\n\nSee my blog post about [User-Defined Order in\nSQL](https://begriffs.com/posts/2018-03-20-user-defined-order.html).\n\n### Usage\n\nBasics\n\n```sql\n-- fractions are precise\n-- this would not work with a float type\nselect 1::rational / 3 * 3 = 1;\n-- =\u003e t\n\n-- provides the usual operations, e.g.\nselect '1/3'::rational + '2/7';\n-- =\u003e 13/21\n\n-- helper \"ratt' type to coerce from tuples\nselect 1 + (i,i+1)::ratt from generate_series(1,5) as i;\n-- =\u003e 3/2, 5/3, 7/4, 9/5, 11/6\n\n-- simplify if desired\nselect rational_simplify('36/12');\n-- =\u003e 3/1\n\n-- convert float to rational\nselect 0.263157894737::float::rational;\n-- =\u003e 5/19\n\n-- convert rational to float\nselect '-1/2'::rational::float;\n-- =\u003e -0.5\n```\n\nNext, reordering items without renumbering surrounding items.\n\nNote we use an integer sequence rather than the default of bigint, and\nexplicitly cast `nextval()`. There is no conversion from bigint to rational\nbecause numerators in this extension can hold at most integer range anyway.\n\n```sql\ncreate sequence todos_seq as integer;\n\ncreate table todos (\n  prio rational unique\n    default nextval('todos_seq')::integer,\n  what text not null\n);\n\ninsert into todos (what) values\n  ('install extension'),\n  ('read about it'),\n  ('try it'),\n  ('profit?');\n\nselect * from todos order by prio asc;\n/*\n┌──────┬───────────────────┐\n│ prio │       what        │\n├──────┼───────────────────┤\n│ 1/1  │ install extension │\n│ 2/1  │ read about it     │\n│ 3/1  │ try it            │\n│ 4/1  │ profit?           │\n└──────┴───────────────────┘\n*/\n\n-- put \"try\" between \"install\" and \"read\"\nupdate todos\nset prio = rational_intermediate(1,2)\nwhere prio = 3;\n\nselect * from todos order by prio asc;\n/*\n┌──────┬───────────────────┐\n│ prio │       what        │\n├──────┼───────────────────┤\n│ 1/1  │ install extension │\n│ 3/2  │ try it            │\n│ 2/1  │ read about it     │\n│ 4/1  │ profit?           │\n└──────┴───────────────────┘\n*/\n\n-- put \"read\" back between \"install\" and \"try\"\nupdate todos\nset prio = rational_intermediate(1,'3/2')\nwhere prio = 2;\n\nselect * from todos order by prio asc;\n/*\n┌──────┬───────────────────┐\n│ prio │       what        │\n├──────┼───────────────────┤\n│ 1/1  │ install extension │\n│ 4/3  │ read about it     │\n│ 3/2  │ try it            │\n│ 4/1  │ profit?           │\n└──────┴───────────────────┘\n*/\n```\n\nThis extension uses Stern-Brocot trees to find efficient intermediate points as fractions in lowest terms. It can continue to split deeper between fractions as much as any practical application requires.\n\nUsing floats, on the other hand, and picking the midpoints between adjacent values runs out of space rapidly (you only need 50-odd inserts at the wrong spot to start hitting problems).\n\n### Installation\n\nClone this repo, go inside and simply run:\n\n```bash\nmake\nsudo make install\n```\n\nThen, in your database:\n\n```sql\ncreate extension pg_rational;\n```\n\n### Caveats\n\nThe `rational_intermediate` function is super fast on typical intervals, but the narrower the range between arguments the longer it takes. We may want to add a max search depth parameter to prevent malicious values from hogging the server.\n\n### Thanks\n\nThis is my first PostgreSQL extension, and these resources were helpful in learning to write it.\n\n* https://www.postgresql.org/docs/10/static/extend-extensions.html\n* https://www.postgresql.org/docs/10/static/xtypes.html\n* http://big-elephants.com/2015-10/writing-postgres-extensions-part-i/\n* https://wiki.postgresql.org/wiki/User-specified_ordering_with_fractions\n* #postgresql and ##c channels on freenode\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbegriffs%2Fpg_rational","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbegriffs%2Fpg_rational","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbegriffs%2Fpg_rational/lists"}