GNU BC: How is the âÂÂmoduloâ (%) with scale other than 0 useful?
Clash Royale CLAN TAG#URR8PPP
up vote
0
down vote
favorite
This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.
When using bc
, the %
operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:
$ bc <<<' scale=0; 27 % 7 '
6
But it fails to give the "integer remainder" if the scale is not zero:
$ bc <<<' scale=10; 27 % 7 '
.0000000003
Why (or how) is this definition of the %
modulo useful?
shell bc
add a comment |Â
up vote
0
down vote
favorite
This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.
When using bc
, the %
operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:
$ bc <<<' scale=0; 27 % 7 '
6
But it fails to give the "integer remainder" if the scale is not zero:
$ bc <<<' scale=10; 27 % 7 '
.0000000003
Why (or how) is this definition of the %
modulo useful?
shell bc
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.
When using bc
, the %
operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:
$ bc <<<' scale=0; 27 % 7 '
6
But it fails to give the "integer remainder" if the scale is not zero:
$ bc <<<' scale=10; 27 % 7 '
.0000000003
Why (or how) is this definition of the %
modulo useful?
shell bc
This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.
When using bc
, the %
operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:
$ bc <<<' scale=0; 27 % 7 '
6
But it fails to give the "integer remainder" if the scale is not zero:
$ bc <<<' scale=10; 27 % 7 '
.0000000003
Why (or how) is this definition of the %
modulo useful?
shell bc
shell bc
asked 1 min ago
Isaac
8,58211241
8,58211241
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
0
down vote
The %
operator is clearly defined in the bc
manual as [a] :
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
Assuming max
has been defined as:
define max(x,y) if(x>y)return(x);return(y)
How is that long definition useful?
Integer remainder.
I'll show both theinternalmod
function and the%
operator results to prove that they are equivalent for some of the next operations.If the numbers are integer, and scale is set to 0, it is the integer remainder function.
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
2 2
$ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
5 5
That is not the same as the math mod function. I'll solve that below.
Decimal remainder.
If the numbern
is a longer decimal number, and we modify the scale, we get:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.123456789 .123456789
$ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000456789 .000456789Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000000089 .000000089That shows that the remainder is made more versatile by that definition.
Now it is: the remainder after the value of scale.
Scale change
The change of scale is required because the numberd
(divisor) may have more decimal digits thann
. In that case, more decimals are needed to have a more precise result from the division:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.12345678883 11 -- .12345678883 11And, if the scale change:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.0000067888287655 16 -- .0000067888287655 16As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of
n
,d
andscale
.
I'll assume that by the comparison between the internalmod
and the %
operator both have been proven to be equivalent.
Confusion.
Be careful because playing with the value ofd
may become confusing:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
print a," ",scale(a),"n"'
.003456789 9And:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
print a," ",scale(a),"n"'
.123456789 9That is: the value of
d
(above 1) will modify the effect of the value of scale set.
Probably, for values of d
different than 1 you should use scale=0 (unless you really know what you are doing).
Math mod.
Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of%
inbc
. The%
operator in bc is using a "truncating division". One that rounds toward0
. That is important for negative values of bothn
and/ord
:$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6The sign of the remainder follows the sign of the
dividend
.$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6While a correct math mod should give an always positive remainder.
To get that (integer) mod function, use:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))And (then) this will work:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[a]
expr % expr
The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).
If scale is set to zero and both expressions are integers this expression is the integer remainder function.
For the bc
code that follows the point where this footnote was introduced to work correctly, define an alias as:
$ alias bc='bc -l "$HOME/.func.bc"'
And create a file named $HOME/.func.bc
that contains (at least):
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
# Max function
define max(x,y) if(x>y)return(x);return(y)
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x)
define sgn (x) if (x<0)x=-1;if(x>0)x=1;return(x) ;
define abs (x) if (x<0) x=-x; return x ;
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))
A mod function for any number (integer or not) may be defined as:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) div=abs(div);return(x - div*floor(x/div))
# Round down to integer below x (toward -inf).
define floor (x) auto os,y;os=scale;scale=0;
y=x/1;if(y>x)y-=1;scale=os;return(y) ;
This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
The %
operator is clearly defined in the bc
manual as [a] :
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
Assuming max
has been defined as:
define max(x,y) if(x>y)return(x);return(y)
How is that long definition useful?
Integer remainder.
I'll show both theinternalmod
function and the%
operator results to prove that they are equivalent for some of the next operations.If the numbers are integer, and scale is set to 0, it is the integer remainder function.
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
2 2
$ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
5 5
That is not the same as the math mod function. I'll solve that below.
Decimal remainder.
If the numbern
is a longer decimal number, and we modify the scale, we get:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.123456789 .123456789
$ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000456789 .000456789Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000000089 .000000089That shows that the remainder is made more versatile by that definition.
Now it is: the remainder after the value of scale.
Scale change
The change of scale is required because the numberd
(divisor) may have more decimal digits thann
. In that case, more decimals are needed to have a more precise result from the division:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.12345678883 11 -- .12345678883 11And, if the scale change:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.0000067888287655 16 -- .0000067888287655 16As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of
n
,d
andscale
.
I'll assume that by the comparison between the internalmod
and the %
operator both have been proven to be equivalent.
Confusion.
Be careful because playing with the value ofd
may become confusing:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
print a," ",scale(a),"n"'
.003456789 9And:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
print a," ",scale(a),"n"'
.123456789 9That is: the value of
d
(above 1) will modify the effect of the value of scale set.
Probably, for values of d
different than 1 you should use scale=0 (unless you really know what you are doing).
Math mod.
Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of%
inbc
. The%
operator in bc is using a "truncating division". One that rounds toward0
. That is important for negative values of bothn
and/ord
:$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6The sign of the remainder follows the sign of the
dividend
.$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6While a correct math mod should give an always positive remainder.
To get that (integer) mod function, use:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))And (then) this will work:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[a]
expr % expr
The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).
If scale is set to zero and both expressions are integers this expression is the integer remainder function.
For the bc
code that follows the point where this footnote was introduced to work correctly, define an alias as:
$ alias bc='bc -l "$HOME/.func.bc"'
And create a file named $HOME/.func.bc
that contains (at least):
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
# Max function
define max(x,y) if(x>y)return(x);return(y)
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x)
define sgn (x) if (x<0)x=-1;if(x>0)x=1;return(x) ;
define abs (x) if (x<0) x=-x; return x ;
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))
A mod function for any number (integer or not) may be defined as:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) div=abs(div);return(x - div*floor(x/div))
# Round down to integer below x (toward -inf).
define floor (x) auto os,y;os=scale;scale=0;
y=x/1;if(y>x)y-=1;scale=os;return(y) ;
This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.
add a comment |Â
up vote
0
down vote
The %
operator is clearly defined in the bc
manual as [a] :
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
Assuming max
has been defined as:
define max(x,y) if(x>y)return(x);return(y)
How is that long definition useful?
Integer remainder.
I'll show both theinternalmod
function and the%
operator results to prove that they are equivalent for some of the next operations.If the numbers are integer, and scale is set to 0, it is the integer remainder function.
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
2 2
$ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
5 5
That is not the same as the math mod function. I'll solve that below.
Decimal remainder.
If the numbern
is a longer decimal number, and we modify the scale, we get:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.123456789 .123456789
$ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000456789 .000456789Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000000089 .000000089That shows that the remainder is made more versatile by that definition.
Now it is: the remainder after the value of scale.
Scale change
The change of scale is required because the numberd
(divisor) may have more decimal digits thann
. In that case, more decimals are needed to have a more precise result from the division:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.12345678883 11 -- .12345678883 11And, if the scale change:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.0000067888287655 16 -- .0000067888287655 16As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of
n
,d
andscale
.
I'll assume that by the comparison between the internalmod
and the %
operator both have been proven to be equivalent.
Confusion.
Be careful because playing with the value ofd
may become confusing:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
print a," ",scale(a),"n"'
.003456789 9And:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
print a," ",scale(a),"n"'
.123456789 9That is: the value of
d
(above 1) will modify the effect of the value of scale set.
Probably, for values of d
different than 1 you should use scale=0 (unless you really know what you are doing).
Math mod.
Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of%
inbc
. The%
operator in bc is using a "truncating division". One that rounds toward0
. That is important for negative values of bothn
and/ord
:$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6The sign of the remainder follows the sign of the
dividend
.$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6While a correct math mod should give an always positive remainder.
To get that (integer) mod function, use:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))And (then) this will work:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[a]
expr % expr
The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).
If scale is set to zero and both expressions are integers this expression is the integer remainder function.
For the bc
code that follows the point where this footnote was introduced to work correctly, define an alias as:
$ alias bc='bc -l "$HOME/.func.bc"'
And create a file named $HOME/.func.bc
that contains (at least):
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
# Max function
define max(x,y) if(x>y)return(x);return(y)
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x)
define sgn (x) if (x<0)x=-1;if(x>0)x=1;return(x) ;
define abs (x) if (x<0) x=-x; return x ;
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))
A mod function for any number (integer or not) may be defined as:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) div=abs(div);return(x - div*floor(x/div))
# Round down to integer below x (toward -inf).
define floor (x) auto os,y;os=scale;scale=0;
y=x/1;if(y>x)y-=1;scale=os;return(y) ;
This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
The %
operator is clearly defined in the bc
manual as [a] :
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
Assuming max
has been defined as:
define max(x,y) if(x>y)return(x);return(y)
How is that long definition useful?
Integer remainder.
I'll show both theinternalmod
function and the%
operator results to prove that they are equivalent for some of the next operations.If the numbers are integer, and scale is set to 0, it is the integer remainder function.
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
2 2
$ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
5 5
That is not the same as the math mod function. I'll solve that below.
Decimal remainder.
If the numbern
is a longer decimal number, and we modify the scale, we get:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.123456789 .123456789
$ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000456789 .000456789Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000000089 .000000089That shows that the remainder is made more versatile by that definition.
Now it is: the remainder after the value of scale.
Scale change
The change of scale is required because the numberd
(divisor) may have more decimal digits thann
. In that case, more decimals are needed to have a more precise result from the division:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.12345678883 11 -- .12345678883 11And, if the scale change:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.0000067888287655 16 -- .0000067888287655 16As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of
n
,d
andscale
.
I'll assume that by the comparison between the internalmod
and the %
operator both have been proven to be equivalent.
Confusion.
Be careful because playing with the value ofd
may become confusing:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
print a," ",scale(a),"n"'
.003456789 9And:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
print a," ",scale(a),"n"'
.123456789 9That is: the value of
d
(above 1) will modify the effect of the value of scale set.
Probably, for values of d
different than 1 you should use scale=0 (unless you really know what you are doing).
Math mod.
Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of%
inbc
. The%
operator in bc is using a "truncating division". One that rounds toward0
. That is important for negative values of bothn
and/ord
:$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6The sign of the remainder follows the sign of the
dividend
.$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6While a correct math mod should give an always positive remainder.
To get that (integer) mod function, use:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))And (then) this will work:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[a]
expr % expr
The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).
If scale is set to zero and both expressions are integers this expression is the integer remainder function.
For the bc
code that follows the point where this footnote was introduced to work correctly, define an alias as:
$ alias bc='bc -l "$HOME/.func.bc"'
And create a file named $HOME/.func.bc
that contains (at least):
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
# Max function
define max(x,y) if(x>y)return(x);return(y)
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x)
define sgn (x) if (x<0)x=-1;if(x>0)x=1;return(x) ;
define abs (x) if (x<0) x=-x; return x ;
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))
A mod function for any number (integer or not) may be defined as:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) div=abs(div);return(x - div*floor(x/div))
# Round down to integer below x (toward -inf).
define floor (x) auto os,y;os=scale;scale=0;
y=x/1;if(y>x)y-=1;scale=os;return(y) ;
This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.
The %
operator is clearly defined in the bc
manual as [a] :
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
Assuming max
has been defined as:
define max(x,y) if(x>y)return(x);return(y)
How is that long definition useful?
Integer remainder.
I'll show both theinternalmod
function and the%
operator results to prove that they are equivalent for some of the next operations.If the numbers are integer, and scale is set to 0, it is the integer remainder function.
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
2 2
$ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"n"'
5 5
That is not the same as the math mod function. I'll solve that below.
Decimal remainder.
If the numbern
is a longer decimal number, and we modify the scale, we get:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.123456789 .123456789
$ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000456789 .000456789Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
print a," ",b,"n"'
.000000089 .000000089That shows that the remainder is made more versatile by that definition.
Now it is: the remainder after the value of scale.
Scale change
The change of scale is required because the numberd
(divisor) may have more decimal digits thann
. In that case, more decimals are needed to have a more precise result from the division:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.12345678883 11 -- .12345678883 11And, if the scale change:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5;
a=internalmod(n,d,scale); b=n%d;
print a," ",scale(a)," -- ", b," ",scale(b),"n"'
.0000067888287655 16 -- .0000067888287655 16As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of
n
,d
andscale
.
I'll assume that by the comparison between the internalmod
and the %
operator both have been proven to be equivalent.
Confusion.
Be careful because playing with the value ofd
may become confusing:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
print a," ",scale(a),"n"'
.003456789 9And:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
print a," ",scale(a),"n"'
.123456789 9That is: the value of
d
(above 1) will modify the effect of the value of scale set.
Probably, for values of d
different than 1 you should use scale=0 (unless you really know what you are doing).
Math mod.
Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of%
inbc
. The%
operator in bc is using a "truncating division". One that rounds toward0
. That is important for negative values of bothn
and/ord
:$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6The sign of the remainder follows the sign of the
dividend
.$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6While a correct math mod should give an always positive remainder.
To get that (integer) mod function, use:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))And (then) this will work:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[a]
expr % expr
The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).
If scale is set to zero and both expressions are integers this expression is the integer remainder function.
For the bc
code that follows the point where this footnote was introduced to work correctly, define an alias as:
$ alias bc='bc -l "$HOME/.func.bc"'
And create a file named $HOME/.func.bc
that contains (at least):
# Internal % operator definition:
define internalmod(n,d,s) auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r)
# Max function
define max(x,y) if(x>y)return(x);return(y)
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x)
define sgn (x) if (x<0)x=-1;if(x>0)x=1;return(x) ;
define abs (x) if (x<0) x=-x; return x ;
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) if(div!=int(div))
"error: divisor should be an integer ";return(0);
return(x - div*int(x/div))
A mod function for any number (integer or not) may be defined as:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) div=abs(div);return(x - div*floor(x/div))
# Round down to integer below x (toward -inf).
define floor (x) auto os,y;os=scale;scale=0;
y=x/1;if(y>x)y-=1;scale=os;return(y) ;
This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.
answered 1 min ago
Isaac
8,58211241
8,58211241
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f478192%2fgnu-bc-how-is-the-modulo-with-scale-other-than-0-useful%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password