branchless abs function
მოდულის გამოთვლის ფუნქცია არის ერთ-ერთი ყველაზე ხშირად გამოყენებადი ფუნქცია სხვადასხვა ტიპის გამოთვლების დროს, შესაბამისად ისეთი აპლიკაციებისთვის, რომელთათვისაც წარმადობა ძალიან მნიშვნელოვანია, მნიშვნელოვანია ასევე ამ ფუნქციის ოპტიმალური გადაწყვეტა. ფუნქციის ყველაზე მარტივი იმპლიმენტაცია ასე გამოიყურება :
int abs( int value ) {
if( value < 0 )
return -value;
return value;
}
პროგრამულ კოდში დამატებითი განშტოებები გარკვეული ტიპის გამომთვლელი მოწყობილობებისათვის, მაგალითად GPU-სთვის, მკვეთრად ართულებს გამოთვლით პროცესს და საბოლოოდ ამცირებს წარმადობას. float-ის შემთხვევაში ჩვენ ვიცით, რომ ყველაზე მაღალი ბიტი გამოყოფილია ნიშნის შესანახად და მისი ცვლილება მოდულის ცვლილებას არ იწვევს, შესაბამისად რიცხვის მოდულის დასათვლელად საკმარისია ყველაზე მაღალ ბიტში დადებითი ნიშნის დაფიქსირება, რაც მოგვცემს სასურველ შედეგს. ამოცანა რთულდება int ტიპის ცვლადების შემთხვევაში, როდესაც ნიშნის შესანახად ცალკე ბიტი არაა გამოყოფილი, არამედ შემუშავებულია შენახვის სპეციალური მექანიზმი, რომელიც გამორიცხავს 2 ცალი 0-იანის არსებობას. იმისათვის, რომ int ცვლადს შევუცვალოთ ნიშანი უნდა შევაბრუნოთ ბიტები და დავუმატოთ 1. სწორედ ამ თვისებას იყენებს მოდულის გამოთვლის ფუნქციის მოდიფიცირებული ვარიანტი:
int abs( int value ) {
const int mask = value >> (sizeof(int)<<3-1);
return (value^mask) - mask;
}
mask-მა შეიძლება მიიღოს მნიშვნელობა 0, როდესაც value არის დადებითი რაც შემდგომი ოპერაციის შემდეგ დააბრუნებს იგივე მნიშვნელობას და ასევე შეიძლება მიიღოს მნიშვნელობა -1(რაც ნიშნიანი ჩაწერის ფორმით გვაძლევს 1-იანებს ყველა ბიტში) , რომლის შემდეგაც XOR ოპერაცია mask-ზე გამოიწვევს ბიტურ ინვერსს ხოლო mask-ის გამოკლება გამოიწვევს 1-იანის დამატებას.
ra enazea es? sizeof(int) tu 2 ia(ishviati shemtxveva) undefined behaviour ikneba C/C++ ze. http://stackoverflow.com/questions/7401888/why-doesnt-left-bit-shift-for-32-bit-integers-work-as-expected-when-used
ReplyDelete(sizeof(int)<<3-1) მოგვცემს 15 როცა int-ის ზომა 2ია და 31-ს როცა 4-ია.
Deleteეს არის უბრალოდ იმისთვის რომ ბოლო ბიტს მივწვდეთ. პრობლემა რომელიც შენ დალინზე ხდება როდესაც წაძვრას ტიპის სიგრძეზე მეტად აკეთებ და არ იცი გარედან 0-ს შემოიტანს თუ 1-ს. მაგ დროს თავი უნდა დაიზღვიო ხოლმე.
ნებისმიერ შემთხვევაში აქ არის კონცეპტი ნაჩვენები ამ მიდგომის.