{"id":21535638,"url":"https://github.com/octoant/low-level-programming","last_synced_at":"2026-05-17T15:07:21.125Z","repository":{"id":107782214,"uuid":"375855554","full_name":"octoant/low-level-programming","owner":"octoant","description":"A collection of assignments and solution of online course at Stepik platform related to low level programming.","archived":false,"fork":false,"pushed_at":"2022-06-20T20:16:32.000Z","size":30650,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-14T19:32:26.004Z","etag":null,"topics":["assembler","c","c-language","intel","low-level-language"],"latest_commit_sha":null,"homepage":"https://gitlab.se.ifmo.ru/programming-languages/cse-programming-languages-fall-2021","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/octoant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-06-10T23:40:53.000Z","updated_at":"2022-06-24T22:06:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"08d8c6b5-a5fe-4fdf-998f-51f080b23280","html_url":"https://github.com/octoant/low-level-programming","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/octoant/low-level-programming","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octoant%2Flow-level-programming","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octoant%2Flow-level-programming/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octoant%2Flow-level-programming/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octoant%2Flow-level-programming/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/octoant","download_url":"https://codeload.github.com/octoant/low-level-programming/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octoant%2Flow-level-programming/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279020649,"owners_count":26086898,"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","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["assembler","c","c-language","intel","low-level-language"],"created_at":"2024-11-24T03:15:49.695Z","updated_at":"2025-10-14T19:32:39.127Z","avatar_url":"https://github.com/octoant.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Assignment: Sepia Filter\n\n---\nSee previous assignment: [Assignment Image Rotation](https://github.com/insaniss/low-level-programming/tree/assignment-image-rotation)\n\n### Sepia Filter\n\nA sepia filter makes an image with vivid colors look like an old, aged photograph.\nMost graphical editors include a sepia filter.\n\nThe filter itself is not hard to code. It recalculates the red, greed, and blue\ncomponents of each pixel based on the old values of red, green and blue.\nMathematically, if we think about a pixel as a three-dimensional vector, the\ntransformation is nothing but a multiplication of a vector by matrix.\n\nLet the new pixel value be (*B* *G* *R*)\u003csup\u003e*T*\u003c/sup\u003e (where *T* superscript \nstands for transposition). *B*, *G*, *R* stand for blue, green, and red levels. \nIn vector from the transformation can be described as follows:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/transform-matrix.png\" alt=\"transform-pixel\" \n       width=\"250\" height=\"70\" /\u003e\n\u003c/p\u003e\n\nIn scalar form, we can rewrite it as\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/transform-system.png\" alt=\"transform-system\"\n       width=\"250\" height=\"70\" /\u003e\n\u003c/p\u003e\n\nWe will have to use saturation arithmetic. It means, that all operations such as\naddition and multiplication are limited to a fixed range between a minimum and\nmaximum value. Out typical machine arithmetic is modular: if the result is greater\nthan the maximum value, we will come from the different side of the range. For \nexample, for `unsigned char`: 200 + 100 = 300 mod 256 = 44. Saturation arithmetic\nimplies that for the same range between 0 and 255 included 200 + 100 = 255 since\nit is the maximum value in range.\n\nC does not implement such arithmetic, so we will have to check for overflows \nmanually. SSE contains instructions that convert floating point values to single\nbyte integers with saturation.\n\nPerforming the transformation in C is easy. It demands direct encoding of the \nmatrix to vector multiplication and taking saturation into account.\n\n```c\n// image_sepia_c_example.c\n#include \u003cinttypes.h\u003e\n\nstruct pixel { uint8_t b, r, g; };\n\nstruct image {\n  uint32_t width, height;\n  struct pixel *array;\n};\n\nstatic unsigned char sat( uint64_t x ) {\n  if ( x \u003c 256 ) return x; return 255;\n}\n\nstatic void sepia_one( struct pixel *const pixel ) {\n  static const float c[3][3] = {\n     { .393f, .769f, .189f },\n     { .349f, .686f, .168f },\n     { .272f, .543f, .131f }\n  };\n  struct pixel const old = *pixel;\n  pixel-\u003er = sat(\n    old.r * c[0][0] + old.g * c[0][1] + old.b * c[0][2]);\n  pixel-\u003eg = sat(\n    old.r * c[1][0] + old.g * c[1][1] + old.b * c[1][2]);\n  pixel-\u003eb = sat(\n    old.r * c[2][0] + old.g * c[2][1] + old.b * c[2][2]);\n}\n\nvoid sepia_c_inplace( struct image *img ) {\n  uint32_t x, y;\n  for ( y = 0; y \u003c img-\u003eheight; y++ )\n    for ( x = 0; x \u003c img-\u003ewidth; x++)\n      sepia_one( pixel_of( *img, x, y ) );\n}\n```\n\nNote that using `uint8_t` or `unsigned char` is very important.\nIn this assignment you have to\n\n* Implement in a separate file a routine to apply a filter to a big par of image\n  (except for the last pixels maybe). It will operate on chunks of multiple pixels \n  at a time using SSE instructions.\n\nThe last few pixels that did not fill the last chunk can be processed one by one \nusing the C code provided in listing above.\n\n* Make sure that both C and assembly versions produce similar results.\n* Compile two programs; the first should use a naive C approach and the second \n  one should use SSE instructions.\n* Compare the time of execution of C and SSE using a huge image as an input \n  (preferably hundreds of megabytes).\n* Repeat the comparison multiple times and calculate the average values for SSE\n  and C;\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctoant%2Flow-level-programming","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foctoant%2Flow-level-programming","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctoant%2Flow-level-programming/lists"}