1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#include <cstdlib>
#include <limits>
// non-const with external linkage, to disable constant folding
extern int large_num ; // invariant: large_num > 0
extern int divisor ; // 1007000000 // invariant: divisor > 0
extern int ubound ; // upper bound on value of int_from_calculation
// invariant: ubound > 0
// invariant: ubound < ( std::numeric_limits<int>::max() - divisor )
// invariant: lower bound on value of int_from_calculation > 0
// optimal if expected average value of int_from_calculation is
// comparable to std::numeric_limits<int>::max() / 2
int foo()
{
int sum = 0 ;
for( int i=0 ; i<large_num ; ++i )
{
sum += std::rand() % ubound ;
sum %= divisor;
}
return sum ;
/*
GCC 4.9 i386 with -std=c++11 -pedantic-errors -Wall -Wextra -fomit-frame-pointer -c -S
__Z3foov:
subl $28, %esp
movl $0, 12(%esp)
movl $0, 8(%esp)
jmp L4
; *** loop starts here ***
L5:
call _rand
movl _ubound, %ecx
cltd
idivl %ecx ; *** division each time through the loop
movl %edx, %eax
addl %eax, 12(%esp)
movl _divisor, %ecx
movl 12(%esp), %eax
cltd
idivl %ecx
movl %edx, 12(%esp)
addl $1, 8(%esp)
L4:
movl _large_num, %eax
cmpl %eax, 8(%esp)
jl L5
; *** and ends here ***
movl 12(%esp), %eax
addl $28, %esp
ret
*/
}
// optimal if expected average value of int_from_calculation is
// much smaller than std::numeric_limits<int>::max() / 2
int bar() // ( a mod c + b mod c ) == (a+b) mod c, verifirs that a+b does not result in UB
{
int sum = 0 ;
const int maxv = std::numeric_limits<int>::max() - ubound ;
for( int i=0 ; i<large_num ; ++i )
{
sum += std::rand() % ubound ;
if( sum > maxv ) sum %= divisor ;
// or: if( sum > maxv ) sum -= divisor ;
// %= is more expensive, -= will execute more often
}
return sum ;
/*
GCC 4.9 i386 with -std=c++11 -pedantic-errors -Wall -Wextra -fomit-frame-pointer -c -S
__Z3barv:
subl $28, %esp
movl $0, 12(%esp)
call __ZNSt14numeric_limitsIiE3maxEv
movl _ubound, %edx
subl %edx, %eax
movl %eax, 4(%esp)
movl $0, 8(%esp)
jmp L8
; *** loop starts here ***
L10:
call _rand
movl _ubound, %ecx
cltd
idivl %ecx
movl %edx, %eax
addl %eax, 12(%esp)
movl 12(%esp), %eax
cmpl 4(%esp), %eax ; *** comparison each time through the loop
jle L9
; *** division only if unavoidable
movl _divisor, %ecx
movl 12(%esp), %eax
cltd
idivl %ecx
movl %edx, 12(%esp)
L9:
addl $1, 8(%esp)
L8:
movl _large_num, %eax
cmpl %eax, 8(%esp)
jl L10
; *** and ends here ***
movl 12(%esp), %eax
addl $28, %esp
ret
*/
}
// optimal if the invariant:
// std::numeric_limits<int>::max() > (large_num*ubound) holds
int baz() // ( a mod c + b mod c ) == (a+b) mod c, a+b does not result in UB
{
int sum = 0 ;
for( int i=0 ; i<large_num ; ++i )
sum += std::rand() % ubound ;
return sum % divisor ;
/*
GCC 4.9 i386 with -std=c++11 -pedantic-errors -Wall -Wextra -fomit-frame-pointer -c -S
__Z3bazv:
subl $28, %esp
movl $0, 12(%esp)
movl $0, 8(%esp)
jmp L13
; *** loop starts here ***
L14:
call _rand
movl _ubound, %ecx
cltd
idivl %ecx
movl %edx, %eax
addl %eax, 12(%esp)
addl $1, 8(%esp)
L13:
movl _large_num, %eax
cmpl %eax, 8(%esp)
jl L14
; *** and ends here ***
movl _divisor, %ecx
movl 12(%esp), %eax
cltd
idivl %ecx ; *** division only once, at the end
movl %edx, %eax
addl $28, %esp
ret
*/
}
|