I have the following function with the variables:
b <- 1 ; d_uhpc <- 4
L_joint <- 8 ; A_bar <- 0.31
A_s <- (A_bar/L_joint)*12
L_unb <- 16 ; f_t <- 1.2
E_s <- 29000 ; E_uhpc <- 8000
ec <- function(x){
theta <- x[3]
eci <- seq(10^-3,1,10^-3)
while (TRUE) {
fc <- eci * E_uhpc
c <- (sqrt(A_s^2 * E_s^2 * eci^2 + fc * A_s * E_s * b * d_uhpc *eci + b^2 * f_t^2 * d_uhpc^2) +
b * f_t * d_uhpc - A_s * E_s *eci)/(b * fc + 2 * b * f_t)
ec <- (-2*theta*c)/L_unb
if (eci > abs(ec)) return("Error") else return(ec)
}
}
# sample rows
strain.analysis <- read.table(text="
L S theta
1 60 6 0.3876484
2 70 6 0.3650651
3 80 6 0.3619457
4 90 6 0.3089947
5 100 6 0.3131211
6 110 6 0.3479024", header=TRUE)
strain.analysis1 <- cbind(strain.analysis, vars = t(apply(strain.analysis,1,ec)))
The function does not understand the conditions correctly and just returns ec for all of the eci values regardless of the condition that it should only return ec when eci < abs(ec)
Below is an example of what I am trying to recreate in R.
Here's what I am thinking: your return statements in the while loop are incorrect as they exit the function ec and not only the while loop. I think your are after break. When I ran your code, with the eci as vector fixed, it only performed one loop for each row in the dataset.
Also, as mentioned before, eci cannot be a vector of length 1000. It has to start at 1E-6 and increment every loop with 1E-6 (per the figure). Your exit criteria are complicated and as we do not know what 0in is it cannot be correctly reconstructed.
Finally, in apply you can call a user-defined function but you have to pass it something.
Having said that, is this what you are after?
b <- 1
d_uhpc <- 4
L_joint <- 8
A_bar <- 0.31
A_s <- (A_bar/L_joint)*12
L_unb <- 16
f_t <- 1.2
E_s <- 29000
E_uhpc <- 8000
eci <- 1E-6
ec <- function(x){
#browser()
theta <- x[3]
while (TRUE) {
fc <- eci * E_uhpc
c <- (sqrt(A_s^2 * E_s^2 * eci^2 + fc * A_s * E_s * b * d_uhpc *eci + b^2 * f_t^2 * d_uhpc^2) +
b * f_t * d_uhpc - A_s * E_s *eci)/(b * fc + 2 * b * f_t)
ec <- (-2*theta*c)/L_unb
if (eci > abs(ec)) break
eci <- eci + 1E-6
}
if (c > d_uhpc | ((max(c(abs(ec), eci), na.rm = TRUE))/(min(c(abs(ec), eci), na.rm = TRUE))) - 1 > 0.05) return(NA_real_) else return(ec)
}
v <- apply(strain.analysis, 1, function(x) ec(x))
strain.analysis1 <- cbind(strain.analysis, v)
The code loops many times for each row of strain,analysis until the break condition is met. Based on the value of ec and eci the function returns either a value of NA_real_.
Here's how my output looks like:
> strain.analysis1
L S theta v
1 60 6 0.3876484 -0.06845568
2 70 6 0.3650651 -0.06447493
3 80 6 0.3619457 -0.06392507
4 90 6 0.3089947 -0.05459143
5 100 6 0.3131211 -0.05531879
6 110 6 0.3479024 -0.06144967
This is a more vectorized approach - it calculates all ec at once and then determines which ec meets the criteria. This means it is fast although it can use up more memory than #Paul van Oppen's solution.
eci <- seq(10^-6,1,10^-6)
fc <- eci * E_uhpc
const <- (sqrt(A_s^2 * E_s^2 * eci^2 + fc * A_s * E_s * b * d_uhpc *eci + b^2 * f_t^2 * d_uhpc^2) +
b * f_t * d_uhpc - A_s * E_s *eci)/(b * fc + 2 * b * f_t)
ec <- function(x){
theta = x[3]
ec = (-2*theta*const)/L_unb
comp = eci > abs(ec)
if (any(comp)) { ## at least one of our eci > abs(ec)
wm = which.max(comp)
if (comp[wm] == FALSE) ##which.max(c(FALSE, FALSE)) will still return something. We need NA_real_ in this case
return (NA_real_)
else
return(ec[wm])
}
else
return(ec[length(x)])
}
cbind(strain.analysis, V = apply(strain.analysis,1,ec))
#> L S theta V
#> 1 60 6 0.3876484 -0.06845568
#> 2 70 6 0.3650651 -0.06447493
#> 3 80 6 0.3619457 -0.06392507
#> 4 90 6 0.3089947 -0.05459143
#> 5 100 6 0.3131211 -0.05531879
#> 6 110 6 0.3479024 -0.06144967
Related
I was wondering if there is a way to convert decimal numbers to ternary, given that there is a function intToBits for converting to binary.
I actually need to convert a character string like
> S0 <- c("Hello Stac")
to base 3. I thought to first convert it to decimal with
> S01 <- utf8ToInt(S0)
> S01
## [1] 72 101 108 108 111 32 83 116 97 99
then convert the result to base 3. I want to obtain something like this:
> S1
## [1] 2200 10202 11000 11010 11022 1012 10002 11022 10121 10200
For practice, I guess you can try to write your own converter function like below
f <- function(x, base = 3) {
q <- c()
while (x) {
q <- c(x %% base, q)
x <- x %/% base
}
# as.numeric(paste0(q, collapse = ""))
sum(q * 10^(rev(seq_along(q) - 1)))
}
or with recursion
f <- function(x, base = 3) {
ifelse(x < base, x, f(x %/% base) * 10 + x %% base)
}
then you can run
> sapply(utf8ToInt(S0),f)
[1] 2200 10202 11000 11000 11010 1012 10002 11022 10121 10200
Nice programming exercise. I have vectorized #ThomasIsCoding's answer to avoid expensive loops over strings and characters within strings. The idea is to loop over digits instead, since Unicode code points do not exceed 21 digits in any base, whereas the total number of characters in a character vector can be orders of magnitude greater.
The function below takes as arguments a character vector x, a base b (from 2 to 10), and a logical flag double. It returns a list res such that res[[i]] is an nchar(x[i])-length vector giving the base-b representation of x[i]. The list elements are double vectors or character vectors depending on double.
utf8ToBase <- function(x, b = 10, double = TRUE) {
## Do some basic checks
stopifnot(is.character(x), !anyNA(x),
is.numeric(b), length(b) == 1L,
b %% 1 == 0, b >= 2, b <= 10)
## Require UTF-8 encoding
x <- enc2utf8(x)
## Operate on concatenation to avoid loop over strings
xx <- paste(x, collapse = "")
ixx <- utf8ToInt(xx)
## Handle trivial case early
if (length(ixx) == 0L) {
el <- if (double) base::double(0L) else character(0L)
res <- rep.int(list(el), length(x))
names(res) <- names(x)
return(res)
}
## Use common field width determined from greatest integer
width <- as.integer(floor(1 + log(max(ixx, 1), base = b)))
res <- rep.int(strrep("0", width), length(ixx))
## Loop over digits
pos <- 1L
pow <- b^(width - 1L)
while (pos <= width) {
quo <- ixx %/% pow
substr(res, pos, pos) <- as.character(quo)
ixx <- ixx - pow * quo
pos <- pos + 1L
pow <- pow %/% b
}
## Discard leading zeros
if (double) {
res <- as.double(res)
if (b == 2 && any(res > 0x1p+53)) {
warning("binary result not guaranteed due to loss of precision")
}
} else {
res <- sub("^0+", "", res)
}
## Return list
res <- split(res, rep.int(gl(length(x), 1L), nchar(x)))
names(res) <- names(x)
res
}
x <- c(foo = "Hello Stack Overflow!", bar = "Hello world!")
utf8ToBase(x, 2)
$foo
[1] 1001000 1100101 1101100 1101100 1101111 100000
[7] 1010011 1110100 1100001 1100011 1101011 100000
[13] 1001111 1110110 1100101 1110010 1100110 1101100
[19] 1101111 1110111 100001
$bar
[1] 1001000 1100101 1101100 1101100 1101111 100000
[7] 1110111 1101111 1110010 1101100 1100100 100001
utf8ToBase(x, 3)
$foo
[1] 2200 10202 11000 11000 11010 1012 10002 11022 10121 10200
[11] 10222 1012 2221 11101 10202 11020 10210 11000 11010 11102
[21] 1020
$bar
[1] 2200 10202 11000 11000 11010 1012 11102 11010 11020 11000
[11] 10201 1020
utf8ToBase(x, 10)
$foo
[1] 72 101 108 108 111 32 83 116 97 99 107 32 79 118 101
[16] 114 102 108 111 119 33
$bar
[1] 72 101 108 108 111 32 119 111 114 108 100 33
Some caveats:
For efficiency, the function concatenates the strings in x rather than looping over them. It throws an error if the concatenation would exceed 2^31-1 bytes, which is the maximum string size allowed by R.
x <- strrep(letters[1:2], 0x1p+30)
log2(sum(nchar(x))) # 31
utf8ToBase(x, 3)
Error in paste(x, collapse = "") : result would exceed 2^31-1 bytes
The largest Unicode code point is 0x10FFFF. The binary representation of this number exceeds 2^53 when interpreted as decimal, so it cannot be stored in a double vector without loss of precision:
x <- sub("^0+", "", paste(rev(as.integer(intToBits(0x10FFFF))), collapse = ""))
x
## [1] "100001111111111111111"
sprintf("%.0f", as.double(x))
## [1] "100001111111111114752"
As a defensive measure, the function warns if 2^53 is exceeded when b = 2 and double = TRUE.
utf8ToBase("\U10FFFF", b = 2, double = TRUE)
[[1]]
[1] 1.000011e+20
Warning message:
In utf8ToBase("\U{10ffff}", b = 2, double = TRUE) :
binary result not guaranteed due to loss of precision
utf8ToBase("\U10FFFF", b = 2, double = FALSE)
[[1]]
[1] "100001111111111111111"
You can use cwhmisc::int2B:
library(cwhmisc)
int2B(utf8ToInt(S0), 3)[[1]] |> as.numeric()
# [1] 2200 10202 11000 11000 11010 1012 10002 11022 10121 10200
I would appreciate any help to specify my brms model below in order to be able to pass multiple columns of weights to the model as illustrated in the stan code below.
I need to do this in brms or stanarm rather than stan directly because I want to use functions of https://github.com/mjskay/tidybayes that are currently not supported by a stanfit object.
#sample data:
dt = read.table(header = TRUE, text = "
n r r/n group treat c2 c1 weights
62 3 0.048387097 1 0 0.1438 1.941115288 1.941115288
96 1 0.010416667 1 0 0.237 1.186583128 1.186583128
17 0 0 0 0 0.2774 1.159882668 3.159882668
41 2 0.048780488 1 0 0.2774 1.159882668 3.159882668
212 170 0.801886792 0 0 0.2093 1.133397521 1.133397521
143 21 0.146853147 1 1 0.1206 1.128993008 1.128993008
143 0 0 1 1 0.1707 1.128993008 2.128993008
143 33 0.230769231 0 1 0.0699 1.128993008 1.128993008
73 62 1.260273973 0 1 0.1351 1.121927228 1.121927228
73 17 0.232876712 0 1 0.1206 1.121927228 1.121927228")
N <- nrow(dt)
n <- dt$n
r <- dt$r
p <- dt$r/n
group <- dt$group
treat <- dt$treat
c1 <- dt$c1
c2 <- dt$c2
w_1 <- dt$weights
w_2 <- dt$weights - 0.01
w_3 <- dt$weights + 0.01/2
w_4 <- dt$weights - 0.01/3
w_5 <- dt$weights + 0.01/4
w_6 <- dt$weights - 0.01/5
w_7 <- dt$weights + 0.01/6
w_8 <- dt$weights + 0.01/7
w_9 <- dt$weights + 0.01/8
w_10 <- dt$weights + 0.01/9
list_bind <- list (N = N,
n = n, r = r, p = p, group = group, treat = treat, c1 = c1, c2 = c2,
weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10)
)
dt_bind <- as.data.frame(list_bind)
#my attempt:
m <-brm(r | trials(n) + weights(weights.w_1:weights.w_10) ~ treat*c2+(1|group),
data=dt_bind, family=binomial(link=logit))
#stan code:
//this is what I want the brms model specification to be able to do
data {
...
real<lower=0> weights[N, 10]; // data block of model weights
}
model {
...
// likelihood
for (n in 1:N)
for (w in 1:10) {
target += weights[n, w] * binomial_logit_lpmf(Y[n] | trials[n], mu[n]);
}
}
Thanks in advance for any help.
I have vector (column data) which contains youtube playback duration in a character string format in R.
x <- c(PT1H8S, PT9M55S, PT13M57S, PT1M5S, PT30M12S, PT1H21M5S, PT6M48S, PT31S, PT2M)
How do I get rid of PT then get the overall duration in seconds format?
Resultant vector should be c(3608, 595, 837, 65, 1812, 4865, 408, 31, 120)
example: PT1H21M5S in the form of seconds = 4865.
(calculated as 1H = 1*3600, 21M = 21*60, 5S = 5*1)
I wrote a little apply loop with regex commands, deleting everything but the seconds, minutes, or hours and then converting everything into seconds.
x <- c("PT1H8S", "PT9M55S", "PT13M57S", "PT1M5S", "PT30M12S", "PT1H21M5S", "PT6M48S")
x2 <- sapply(x, function(i){
t <- as.numeric(gsub("^(.*)M|^(.*)H|S$", "", i))
if(grepl("M", i)) t <- t + as.numeric(gsub("^(.*)PT|^(.*)H|M(.*)$", "",i)) * 60
if(grepl("H", i)) t <- t + as.numeric(gsub("^(.*)PT|H(.*)$", "",i)) * 3600
t
})
x2
PT1H8S PT9M55S PT13M57S PT1M5S PT30M12S PT1H21M5S PT6M48S
3608 595 837 65 1812 4865 408
EDIT: Per request
x <- c("PT1H8S", "PT9M55S", "PT13M57S", "PT1M5S", "PT30M12S", "PT1H21M5S", "PT6M48S", "PT31S", "PT2M")
x2 <- sapply(x, function(i){
t <- 0
if(grepl("S", i)) t <- t + as.numeric(gsub("^(.*)PT|^(.*)M|^(.*)H|S$", "", i))
if(grepl("M", i)) t <- t + as.numeric(gsub("^(.*)PT|^(.*)H|M(.*)$", "",i)) * 60
if(grepl("H", i)) t <- t + as.numeric(gsub("^(.*)PT|H(.*)$", "",i)) * 3600
t
})
x2
PT1H8S PT9M55S PT13M57S PT1M5S PT30M12S PT1H21M5S PT6M48S PT31S PT2M
3608 595 837 65 1812 4865 408 31 120
This should cover all the cases. If there are more, the trick is to alter the regex. ^ is the beginning of the character vector, $ is the end. (.*) is everything. So ^(.*)H means everything between beginning and H. We replace this with nothing.
Here's a dplyr and stringr solution:
df %>%
# extract hours, minutes, and seconds and convert to numeric:
mutate(
h = as.numeric(str_extract(x, "(?<=PT)\\d+(?=H)")),
m = as.numeric(str_extract(x, "(?<=PT|H)\\d+(?=M)")),
s = as.numeric(str_extract(x, "(?<=PT|H|M)\\d+(?=S)"))
) %>%
# replace NA with 0:
mutate(
across(everything(), replace_na, 0)
) %>%
# calculate time in seconds:
mutate(sec = h*3600+m*60+s)
x h m s sec
1 PT1H8S 1 0 8 3608
2 PT9M55S 0 9 55 595
3 PT13M57S 0 13 57 837
4 PT1M5S 0 1 5 65
5 PT30M12S 0 30 12 1812
6 PT1H21M5S 1 21 5 4865
7 PT6M48S 0 6 48 408
8 PT31S 0 0 31 31
9 PT2M 0 2 0 120
Data:
df <- data.frame(x = c("PT1H8S", "PT9M55S", "PT13M57S", "PT1M5S", "PT30M12S", "PT1H21M5S", "PT6M48S", "PT31S", "PT2M"))
You can use Lubridate package:
library(lubridate)
x <- c("PT1H8S", "PT9M55S", "PT13M57S", "PT1M5S", "PT30M12S", "PT1H21M5S", "PT6M48S")
x2 <- as.numeric(duration(x))
x2
[1] 3608 595 837 65 1812 4865 408
I put the section of code in bold that seems to be the problem. Here is the code:
## price impact analysis
rm(list=ls())
### import data from excel spreadsheets
chtr_trades <- read.csv("F:/FRE 6951 Mkt Micro Struc/CHTRTRADES.csv")
chtr_quotes <- read.csv("F:/FRE 6951 Mkt Micro Struc/CHTRQUOTES.csv")
## initialize bid ask
max_bid <- NULL
min_ask <- NULL
### cleans data
maxrm <- function(x) {
max(x, na.rm=TRUE)
}
minrm <- function(x) {
min(x, na.rm=TRUE)
}
## retrieve max bid and ask for each iteration
max_bid<- tapply(chtr_quotes[,4],chtr_quotes[,3], maxrm)
min_ask<- tapply(chtr_quotes[,5],chtr_quotes[,3], minrm)
time <- levels(chtr_quotes[,3])
## calculate previous second midpoint
midpoint <- (min_ask + max_bid)/2
askbidtime <- data.frame(midpoint,time,max_bid,min_ask)
row.names(askbidtime) <- seq(nrow(askbidtime))
askbidtime[,2] <- as.POSIXct(askbidtime[,2], format="%H:%M:%S")
ordered.askbidtime <- askbidtime[order(askbidtime$time),]
row.names(ordered.askbidtime) <- seq(nrow(ordered.askbidtime))
chtr_trades_revised <-chtr_trades[which(as.POSIXct(chtr_trades[,3],format="%H:%M:%S") %in% ordered.askbidtime[,2]),]
midpoint<-NULL
midpoint[1:5] <- NA
for(i in 6:3917) {
midpoint[i] <- as.numeric(ordered.askbidtime[which(ordered.askbidtime[,2]==as.POSIXct(chtr_trades_revised[i,3],format="%H:%M:%S"))-1,1])
}
***## sign trades
chtr_trades_revised$midpoint
chtr_trades_revised$midpoint <- midpoint
for(i in 6:3917) {
if((!is.na(chtr_trades_revised$midpoint[i])) & (chtr_trades_revised$midpoint[i] > chtr_trades_revised$PRICE[i])) {
chtr_trades_revised$signed_volume <- -chtr_trades_revised$SIZE
}
if((!is.na(chtr_trades_revised$midpoint[i])) & (chtr_trades_revised$midpoint[i] < chtr_trades_revised$PRICE[i])) {
chtr_trades_revised$signed_volume <- chtr_trades_revised$SIZE
}
}***
Here are the results. In the last column rows 4062 and 4054 should be positive but it makes the entire column negative:
SYMBOL DATE TIME PRICE SIZE midpoint signed_volume
4060 CHTR 20130718 2014-08-26 15:59:44 124.46 100 124.485 -100
4061 CHTR 20130718 2014-08-26 15:59:52 124.46 100 124.495 -100
4062 CHTR 20130718 2014-08-26 15:59:55 124.52 100 124.490 -100
4063 CHTR 20130718 2014-08-26 15:59:58 124.53 100 124.410 -100
4064 CHTR 20130718 2014-08-26 16:00:00 124.57 7951 124.550 -7951
4065 CHTR 20130718 2014-08-26 16:00:00 124.53 100 124.550 -100
Here's a cute way:
foo<- 1:10
threshold <- 5
foo<- foo*(-1)^(foo < threshold)
foo
[1] -1 -2 -3 -4 5 6 7 8 9 10
Another method:
foo = 1:10 ; threshold = 5
foo
[1] 1 2 3 4 5 6 7 8 9 10
foo = ifelse(foo>=threshold, foo, -foo)
foo
[1] -1 -2 -3 -4 5 6 7 8 9 10
How to calculate modulus of 5^55 modulus 221 without much use of calculator?
I guess there are some simple principles in number theory in cryptography to calculate such things.
Okay, so you want to calculate a^b mod m. First we'll take a naive approach and then see how we can refine it.
First, reduce a mod m. That means, find a number a1 so that 0 <= a1 < m and a = a1 mod m. Then repeatedly in a loop multiply by a1 and reduce again mod m. Thus, in pseudocode:
a1 = a reduced mod m
p = 1
for(int i = 1; i <= b; i++) {
p *= a1
p = p reduced mod m
}
By doing this, we avoid numbers larger than m^2. This is the key. The reason we avoid numbers larger than m^2 is because at every step 0 <= p < m and 0 <= a1 < m.
As an example, let's compute 5^55 mod 221. First, 5 is already reduced mod 221.
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
Therefore, 5^55 = 112 mod 221.
Now, we can improve this by using exponentiation by squaring; this is the famous trick wherein we reduce exponentiation to requiring only log b multiplications instead of b. Note that with the algorithm that I described above, the exponentiation by squaring improvement, you end up with the right-to-left binary method.
a1 = a reduced mod m
p = 1
while (b > 0) {
if (b is odd) {
p *= a1
p = p reduced mod m
}
b /= 2
a1 = (a1 * a1) reduced mod m
}
Thus, since 55 = 110111 in binary
1 * (5^1 mod 221) = 5 mod 221
5 * (5^2 mod 221) = 125 mod 221
125 * (5^4 mod 221) = 112 mod 221
112 * (5^16 mod 221) = 112 mod 221
112 * (5^32 mod 221) = 112 mod 221
Therefore the answer is 5^55 = 112 mod 221. The reason this works is because
55 = 1 + 2 + 4 + 16 + 32
so that
5^55 = 5^(1 + 2 + 4 + 16 + 32) mod 221
= 5^1 * 5^2 * 5^4 * 5^16 * 5^32 mod 221
= 5 * 25 * 183 * 1 * 1 mod 221
= 22875 mod 221
= 112 mod 221
In the step where we calculate 5^1 mod 221, 5^2 mod 221, etc. we note that 5^(2^k) = 5^(2^(k-1)) * 5^(2^(k-1)) because 2^k = 2^(k-1) + 2^(k-1) so that we can first compute 5^1 and reduce mod 221, then square this and reduce mod 221 to obtain 5^2 mod 221, etc.
The above algorithm formalizes this idea.
To add to Jason's answer:
You can speed the process up (which might be helpful for very large exponents) using the binary expansion of the exponent. First calculate 5, 5^2, 5^4, 5^8 mod 221 - you do this by repeated squaring:
5^1 = 5(mod 221)
5^2 = 5^2 (mod 221) = 25(mod 221)
5^4 = (5^2)^2 = 25^2(mod 221) = 625 (mod 221) = 183(mod221)
5^8 = (5^4)^2 = 183^2(mod 221) = 33489 (mod 221) = 118(mod 221)
5^16 = (5^8)^2 = 118^2(mod 221) = 13924 (mod 221) = 1(mod 221)
5^32 = (5^16)^2 = 1^2(mod 221) = 1(mod 221)
Now we can write
55 = 1 + 2 + 4 + 16 + 32
so 5^55 = 5^1 * 5^2 * 5^4 * 5^16 * 5^32
= 5 * 25 * 625 * 1 * 1 (mod 221)
= 125 * 625 (mod 221)
= 125 * 183 (mod 183) - because 625 = 183 (mod 221)
= 22875 ( mod 221)
= 112 (mod 221)
You can see how for very large exponents this will be much faster (I believe it's log as opposed to linear in b, but not certain.)
/* The algorithm is from the book "Discrete Mathematics and Its
Applications 5th Edition" by Kenneth H. Rosen.
(base^exp)%mod
*/
int modular(int base, unsigned int exp, unsigned int mod)
{
int x = 1;
int power = base % mod;
for (int i = 0; i < sizeof(int) * 8; i++) {
int least_sig_bit = 0x00000001 & (exp >> i);
if (least_sig_bit)
x = (x * power) % mod;
power = (power * power) % mod;
}
return x;
}
5^55 mod221
= ( 5^10 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 5^10) mod221 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( 77 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 77 * 5^10) mod221 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( 183 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 183 * 5^10) mod221 * 5^10 * 5^10 * 5^5) mod221
= ( 168 * 5^10 * 5^10 * 5^5) mod221
= ( ( 168 * 5^10) mod 221 * 5^10 * 5^5) mod221
= ( 118 * 5^10 * 5^5) mod221
= ( ( 118 * 5^10) mod 221 * 5^5) mod221
= ( 25 * 5^5) mod221
= 112
What you're looking for is modular exponentiation, specifically modular binary exponentiation. This wikipedia link has pseudocode.
Chinese Remainder Theorem comes to mind as an initial point as 221 = 13 * 17. So, break this down into 2 parts that get combined in the end, one for mod 13 and one for mod 17. Second, I believe there is some proof of a^(p-1) = 1 mod p for all non zero a which also helps reduce your problem as 5^55 becomes 5^3 for the mod 13 case as 13*4=52. If you look under the subject of "Finite Fields" you may find some good results on how to solve this.
EDIT: The reason I mention the factors is that this creates a way to factor zero into non-zero elements as if you tried something like 13^2 * 17^4 mod 221, the answer is zero since 13*17=221. A lot of large numbers aren't going to be prime, though there are ways to find large primes as they are used a lot in cryptography and other areas within Mathematics.
This is part of code I made for IBAN validation. Feel free to use.
static void Main(string[] args)
{
int modulo = 97;
string input = Reverse("100020778788920323232343433");
int result = 0;
int lastRowValue = 1;
for (int i = 0; i < input.Length; i++)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
if (i > 0)
{
lastRowValue = ModuloByDigits(lastRowValue, modulo);
}
result += lastRowValue * int.Parse(input[i].ToString());
}
result = result % modulo;
Console.WriteLine(string.Format("Result: {0}", result));
}
public static int ModuloByDigits(int previousValue, int modulo)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
return ((previousValue * 10) % modulo);
}
public static string Reverse(string input)
{
char[] arr = input.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
Jason's answer in Java (note i < exp).
private static void testModulus() {
int bse = 5, exp = 55, mod = 221;
int a1 = bse % mod;
int p = 1;
System.out.println("1. " + (p % mod) + " * " + bse + " = " + (p % mod) * bse + " mod " + mod);
for (int i = 1; i < exp; i++) {
p *= a1;
System.out.println((i + 1) + ". " + (p % mod) + " * " + bse + " = " + ((p % mod) * bse) % mod + " mod " + mod);
p = (p % mod);
}
}
Just provide another implementation of Jason's answer by C.
After discussing with my classmates, based on Jason's explanation, I like the recursive version more if you don't care about the performance very much:
For example:
#include<stdio.h>
int mypow( int base, int pow, int mod ){
if( pow == 0 ) return 1;
if( pow % 2 == 0 ){
int tmp = mypow( base, pow >> 1, mod );
return tmp * tmp % mod;
}
else{
return base * mypow( base, pow - 1, mod ) % mod;
}
}
int main(){
printf("%d", mypow(5,55,221));
return 0;
}
This is called modular exponentiation(https://en.wikipedia.org/wiki/Modular_exponentiation).
Let's assume you have the following expression:
19 ^ 3 mod 7
Instead of powering 19 directly you can do the following:
(((19 mod 7) * 19) mod 7) * 19) mod 7
But this can take also a long time due to a lot of sequential multipliations and so you can multiply on squared values:
x mod N -> x ^ 2 mod N -> x ^ 4 mod -> ... x ^ 2 |log y| mod N
Modular exponentiation algorithm makes assumptions that:
x ^ y == (x ^ |y/2|) ^ 2 if y is even
x ^ y == x * ((x ^ |y/2|) ^ 2) if y is odd
And so recursive modular exponentiation algorithm will look like this in java:
/**
* Modular exponentiation algorithm
* #param x Assumption: x >= 0
* #param y Assumption: y >= 0
* #param N Assumption: N > 0
* #return x ^ y mod N
*/
public static long modExp(long x, long y, long N) {
if(y == 0)
return 1 % N;
long z = modExp(x, Math.abs(y/2), N);
if(y % 2 == 0)
return (long) ((Math.pow(z, 2)) % N);
return (long) ((x * Math.pow(z, 2)) % N);
}
Special thanks to #chux for found mistake with incorrect return value in case of y and 0 comparison.