{"id":9802,"date":"2020-10-19T10:10:11","date_gmt":"2020-10-19T08:10:11","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=9802"},"modified":"2023-10-24T10:50:09","modified_gmt":"2023-10-24T08:50:09","slug":"niedokladnosci-numeryczne-w-funkcjach-trygonometrycznych-w-fpu-na-platformie-x86","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/niedokladnosci-numeryczne-w-funkcjach-trygonometrycznych-w-fpu-na-platformie-x86\/","title":{"rendered":"Niedok\u0142adno\u015bci numeryczne w funkcjach trygonometrycznych w FPU na platformie x86"},"content":{"rendered":"\n<p>W trakcie rozwoju oprogramowania niejednokrotnie zachodzi potrzeba wdro\u017cenia projektu mimo istniej\u0105cych, nierozwi\u0105zanych b\u0142\u0119d\u00f3w. <\/p>\n\n\n\n<p>Zwykle dzieje si\u0119 to w wyniku presji czasu. Wraz z rozwojem elektroniki mo\u017cna spodziewa\u0107 si\u0119, \u017ce sytuacja powy\u017csza mo\u017ce dotkn\u0105\u0107 r\u00f3wnie\u017c procesor\u00f3w. W architekturze x86 na przestrzeni kilkudziesi\u0119ciu lat wykryto pewn\u0105 liczb\u0119 b\u0142\u0119d\u00f3w, od bardzo powa\u017cnych luk bezpiecze\u0144stwa (jak Spectre i Meltdown), po takie, kt\u00f3rych przeci\u0119tny u\u017cytkownik mo\u017ce nigdy nie zauwa\u017cy\u0107 (jak FDIV \u2013 niedok\u0142adno\u015b\u0107 przy dzieleniu liczb zmiennoprzecinkowych). W tym artykule przybli\u017cone b\u0119dzie inne, mniej znane zachowanie FPU maj\u0105ce wp\u0142yw na dok\u0142adno\u015b\u0107 operacji sinus oraz cosinus. Cho\u0107 zalicza si\u0119 do tych na og\u00f3\u0142 o mniejszym wp\u0142ywie, mo\u017ce jednak przyprawi\u0107 programist\u0119 o b\u00f3l g\u0142owy, szczeg\u00f3lnie je\u015bli zale\u017cy mu na du\u017cej dok\u0142adno\u015bci oblicze\u0144. Na ten b\u0142\u0105d autor natkn\u0105\u0142 si\u0119 podczas testowania sterownika PLC i by\u0142o zaskakuj\u0105ce jak du\u017ca mo\u017ce by\u0107 skala b\u0142\u0119du.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Liczby sta\u0142o- a zmiennoprzecinkowe<\/h2>\n\n\n\n<p>Na komputerach, kt\u00f3re wszyscy znamy, tj. operuj\u0105cych w systemie binarnym mo\u017cna wykonywa\u0107 dzia\u0142ania na liczbach ca\u0142kowitych, sta\u0142o- lub zmiennoprzecinkowych. Pierwszych z nich na \u0142amach tego bloga nie trzeba szczeg\u00f3lnie wyja\u015bnia\u0107. Sta\u0142oprzecinkowe, podobnie jak ca\u0142kowite, na kolejnych bitach przechowuj\u0105 kolejne pot\u0119gi dw\u00f3jki, np. 110101,11b = 2<sup>5<\/sup>+2<sup>4<\/sup>+2<sup>2<\/sup>+2<sup>0<\/sup>+2<sup>-1<\/sup>+2<sup>-2<\/sup> = 53,75. Takie typy mo\u017cna spotka\u0107 np. w bibliotece CMSIS DSP, gdzie zdefiniowane s\u0105: Q7, Q15 oraz Q31. Jeden bit przechowuje w nich znak, a pozosta\u0142e stanowi\u0105 cz\u0119\u015b\u0107 u\u0142amkow\u0105. W przypadku warto\u015bci ujemnych obowi\u0105zuje w nich uzupe\u0142nienie do dw\u00f3ch, zatem 11111111b w typie Q7 odpowiada liczbie -1\/128.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-1.png\"><img decoding=\"async\" width=\"976\" height=\"89\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-1.png\" alt=\"znak, wyk\u0142adnik, mantysa\" class=\"wp-image-9805\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-1.png 976w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-1-300x27.png 300w\" sizes=\"(max-width: 976px) 100vw, 976px\" \/><\/a><\/figure>\n\n\n\n<p>Liczby zmiennoprzecinkowe to osobna koncepcja zdefiniowana w normie IEEE-754. Koduje si\u0119 je przy pomocy trzech p\u00f3l bitowych: znaku, wyk\u0142adnika i mantysy, stosuj\u0105c do nich specjalne regu\u0142y. Mianowicie, wyk\u0142adnik dla typu double sk\u0142ada si\u0119 z jedenastu bit\u00f3w. Najmniejszy mo\u017cliwy wyk\u0142adnik, (tj, -1022) jest kodowany w postaci: 00000000001b, natomiast najwy\u017cszy mo\u017cliwy, jako: 11111111110b. Mantysa przechowuje liczb\u0119 podobnie jak liczby sta\u0142oprzecinkowe, jednak z pomini\u0119ciem jedynki na najstarszym bicie. Przyjmuje si\u0119, \u017ce liczba r\u00f3\u017cna od zera zawsze t\u0119 jedynk\u0119 musi mie\u0107, st\u0105d dobiera si\u0119 wyk\u0142adnik tak, aby jedynk\u0119 wysun\u0105\u0107 na bit o jeden wy\u017cszy ni\u017c liczba bit\u00f3w mantysy. Proces ten nazywa si\u0119 normalizacj\u0105, a wspomniany bit musi by\u0107 uwzgl\u0119dniony przy wszystkich dzia\u0142aniach. Gdy wynik jest zbyt ma\u0142y, aby da\u0142o si\u0119 spe\u0142ni\u0107 ten warunek w wyk\u0142adniku pojawiaj\u0105 si\u0119 same zera a liczby z tego nazywa si\u0119 nieznormalizowanymi. Mantysa reprezentuje wtedy liczb\u0119 postaci 0,xxx&#8230;xxx, zamiast 1,xxx&#8230;xxx.<\/p>\n\n\n\n<p>Liczba zmiennoprzecinkowa mo\u017ce przechowywa\u0107 liczby od niewielkich u\u0142amk\u00f3w po bardzo du\u017ce warto\u015bci: 3.4E+38 dla liczb pojedynczej precyzji i +1.7E+308 dla podw\u00f3jnej precyzji. Aby uzmys\u0142owi\u0107 sobie jak du\u017ce to liczby, warto pos\u0142u\u017cy\u0107 si\u0119 przyk\u0142adem: szacuje si\u0119, \u017ce we wszech\u015bwiecie znajduje si\u0119 mi\u0119dzy 10<sup>78<\/sup>&nbsp;a 10<sup>82<\/sup>&nbsp;atom\u00f3w. Z drugiej strony obydwa te typy zajmuj\u0105 odpowiednio 32 i 64 bity. Wynikaj\u0105 z tego dwa fakty:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Liczba zmiennoprzecinkowa mo\u017ce przechowa\u0107 tylko tyle r\u00f3\u017cnych warto\u015bci ile odpowiadaj\u0105ce im uint32_t i uint64_t. Poniewa\u017c 2<sup>32<\/sup> &lt; 3.4E+38 oraz 2<sup>64<\/sup> &lt; +1.7E+308, wiele po\u015brednich warto\u015bci nie mo\u017ce by\u0107 zapisanych przy pomocy tego typu.<\/li>\n\n\n\n<li>&nbsp;U\u017cywaj\u0105c unii j\u0119zyka C mo\u017cemy mie\u0107 dost\u0119p do &nbsp;reprezentacji bitowej liczby zmiennoprzecinkowej. Istotnie, s\u0105siaduj\u0105ce ze sob\u0105 warto\u015bci float czy double w reprezentacji bitowej uintNN_t b\u0119d\u0105 te\u017c kolejnymi, s\u0105siaduj\u0105cymi ze sob\u0105 liczbami ca\u0142kowitymi.<\/li>\n<\/ol>\n\n\n\n<p>T\u0119 drug\u0105 w\u0142a\u015bciwo\u015b\u0107 wygodnie jest u\u017cy\u0107 do por\u00f3wnywania. Np. znaj\u0105c dok\u0142adny, spodziewany wynik, aby sprawdzi\u0107 dok\u0142adno\u015b\u0107 danej operacji wystarczy odj\u0105\u0107 reprezentacje bitowe obu liczb. Jednostk\u0119 otrzymanego wyniku okre\u015bla si\u0119 angielskim skr\u00f3towcem ULP (units in the last place). Przez wiele lat dok\u0142adno\u015b\u0107 instrukcji FSIN w podr\u0119czniku dla architektury Intela by\u0142a okre\u015blona jako nie wi\u0119ksza ni\u017c 2 ULP. Czy tak jest w istocie?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Operacja FSIN<\/h2>\n\n\n\n<p>Funkcje trygonometryczne mo\u017cna obliczy\u0107 w spos\u00f3b analityczny dzi\u0119ki aproksymacji. &nbsp;Obliczenie odbywa si\u0119 zwykle w dw\u00f3ch etapach:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>argument, je\u015bli wykracza poza podstawowy okres, dla kt\u00f3rego dokonano aproksymacji, jest redukowany do tego podstawowego zakresu. Realizuje si\u0119 t\u0119 redukcj\u0119 poprzez odj\u0119cie wielokrotno\u015bci liczby \u03c0 od argumentu, np. 3\/2 \u03c0 b\u0119dzie zredukowane do \u00bd \u03c0<\/li>\n\n\n\n<li>tak zredukowany argument jest podawany na wej\u015bcie funkcji aproksymuj\u0105cej sinus przy pomocy np. wielomianu (inna technika, cz\u0119sto implementowana w sprz\u0119cie to CORDIC)<\/li>\n<\/ul>\n\n\n\n<p>Przy wystarczaj\u0105co dok\u0142adnej aproksymacji i niewielkim argumencie dok\u0142adno\u015b\u0107 mo\u017ce by\u0107 taka jak to by\u0142o zapowiedziane. \u0179r\u00f3d\u0142em niedok\u0142adno\u015bci jest wspomniana wy\u017cej redukcja argumentu. Przy tej redukcji wykorzystywana jest sta\u0142a \u03c0, zapisana w strukturze koprocesora arytmetycznego w postaci 66-bitowej sta\u0142ej. To za ma\u0142o aby uzyska\u0107 dok\u0142adny wynik. Zobaczmy to na przyk\u0142adzie liczby podw\u00f3jnej precyzji bliskiej \u03c0 (typu double \u2013 rozmiar mantysy wynosi wtedy 53 bity).<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-2.png\"><img decoding=\"async\" width=\"1322\" height=\"189\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-2.png\" alt=\"\" class=\"wp-image-9804\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-2.png 1322w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-2-300x43.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86-2-1024x146.png 1024w\" sizes=\"(max-width: 1322px) 100vw, 1322px\" \/><\/a><\/figure>\n\n\n\n<p>R\u00f3\u017cnica mi\u0119dzy argumentem z 53 bitami mantysy a wy\u017cej wspomnian\u0105 aproksymacj\u0105 da jedynie 13 bit\u00f3w dok\u0142adnego wyniku. Dodatkowo, im wi\u0119kszy argument tym b\u0142\u0105d b\u0119dzie si\u0119 kumulowa\u0142.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowanie<\/h2>\n\n\n\n<p>W przypadku tej nieprawid\u0142owo\u015bci zdecydowano na dodanie dok\u0142adniejszego wyja\u015bnienia nt. precyzji w dokumentacji zamiast poprawki w sprz\u0119cie, najprawdopodobniej z powodu kompatybilno\u015bci. W ten spos\u00f3b unikni\u0119to sytuacji, w kt\u00f3rej procesory z tej samej rodziny generuj\u0105 r\u00f3\u017cne wyniki. B\u0142\u0119dy, o kt\u00f3rych mowa, maj\u0105 du\u017ce warto\u015bci wzgl\u0119dne, ale w liczbach bezwzgl\u0119dnych s\u0105 to niewielkie liczby, bliskie zeru. Przypuszczam, \u017ce taki jest pow\u00f3d, dla kt\u00f3rego nie dostrze\u017cono tego b\u0142\u0119du w czasie produkcji i to za tym sta\u0142a taka, a nie inna decyzja producenta w sprawie odpowiedzi na zg\u0142oszenie b\u0142\u0119du. &nbsp;Nale\u017cy zatem pomy\u015ble\u0107 o tym, aby ograniczy\u0107 argument wej\u015bciowy, w celu ograniczenia b\u0142\u0119d\u00f3w numerycznych, kt\u00f3re wnosz\u0105 funkcje trygonometryczne.<\/p>\n\n\n\n<p>Warto wspomnie\u0107, \u017ce systemy uniksowe nie wywo\u0142uj\u0105 na og\u00f3\u0142 instrukcji FSIN, poniewa\u017c w bibliotece GLIBC znajduje si\u0119 implementacja omijaj\u0105ca FPU. Jak podaje Jason Orendorff na Stack Overflow, jest ona szybsza ni\u017c obliczenie z wykorzystaniem koprocesora (za to b\u0142\u0119dy ULP por\u00f3wnywalne).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bibliografia<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Lista b\u0142\u0119d\u00f3w procesor\u00f3w x86: <a href=\"https:\/\/wiki.osdev.org\/CPU_Bugs\" rel=\"nofollow\" >https:\/\/wiki.osdev.org\/CPU_Bugs<\/a><\/li>\n\n\n\n<li>Szczeg\u00f3\u0142owy artyku\u0142 Bruce\u2019a Dawsona na ten sam temat: <a href=\"https:\/\/randomascii.wordpress.com\/2014\/10\/09\/intel-underestimates-error-bounds-by-1-3-quintillion\/\" rel=\"nofollow\" >https:\/\/randomascii.wordpress.com\/2014\/10\/09\/intel-underestimates-error-bounds-by-1-3-quintillion\/<\/a><\/li>\n\n\n\n<li>Odpowied\u017a Intela na zg\u0142oszone nieprawid\u0142owo\u015bci: <a href=\"https:\/\/software.intel.com\/blogs\/2014\/10\/09\/fsin-documentation-improvements-in-the-intel-64-and-ia-32-architectures-software\" rel=\"nofollow\" >https:\/\/software.intel.com\/blogs\/2014\/10\/09\/fsin-documentation-improvements-in-the-intel-64-and-ia-32-architectures-software<\/a><\/li>\n\n\n\n<li>Dokumentacja procesor\u00f3w Intel (Software Developer\u2019s Manual): <a href=\"https:\/\/software.intel.com\/content\/dam\/develop\/public\/us\/en\/documents\/325462-sdm-vol-1-2abcd-3abcd.pdf\" rel=\"nofollow\" >https:\/\/software.intel.com\/content\/dam\/develop\/public\/us\/en\/documents\/325462-sdm-vol-1-2abcd-3abcd.pdf<\/a><\/li>\n\n\n\n<li>Wizualne przedstawienie precyzji funkcji trygonometrycznych dla architektur x86: <a href=\"http:\/\/notabs.org\/fpuaccuracy\/index.htm\" rel=\"nofollow\" >http:\/\/notabs.org\/fpuaccuracy\/index.htm<\/a><\/li>\n\n\n\n<li>Pytanie ze Stack Overflow nt. Implementacji funkcji trygonometrycznych: <a href=\"https:\/\/stackoverflow.com\/questions\/2284860\/how-does-c-compute-sin-and-other-math-functions\" rel=\"nofollow\" >https:\/\/stackoverflow.com\/questions\/2284860\/how-does-c-compute-sin-and-other-math-functions<\/a><\/li>\n<\/ul>\n\n\n\n<p>Przyk\u0142adowy kod umo\u017cliwiaj\u0105cy samodzielne sprawdzenie prezentowanych tutaj rewelacji:&nbsp;<a href=\"https:\/\/gitlab.com\/skocjan\/sin_fpu.git\" rel=\"nofollow\" >https:\/\/gitlab.com\/skocjan\/sin_fpu.git<\/a><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;9802&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( vote: 1)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Niedok\u0142adno\u015bci numeryczne w funkcjach trygonometrycznych w FPU na platformie x86&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( vote: 1)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W trakcie rozwoju oprogramowania niejednokrotnie zachodzi potrzeba wdro\u017cenia projektu mimo istniej\u0105cych, nierozwi\u0105zanych b\u0142\u0119d\u00f3w. Zwykle dzieje si\u0119 to w wyniku presji &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/niedokladnosci-numeryczne-w-funkcjach-trygonometrycznych-w-fpu-na-platformie-x86\/\">Continued<\/a><\/p>\n","protected":false},"author":260,"featured_media":9809,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[],"class_list":["post-9802","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2020\/10\/Niedok\u0142adno\u015bci-numeryczne-w-funkcjach-trygonometrycznych-w-FPU-na-platformie-x86.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/9802"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/260"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=9802"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/9802\/revisions"}],"predecessor-version":[{"id":25192,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/9802\/revisions\/25192"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/9809"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=9802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=9802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=9802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}