# Speed up \`x::Bool ^ y::Float64\`

**URL:** <https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601>\
**Category:** General Usage\
**Created:** [November 21, 2022, 7:43pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601 "2022-11-21T19:43:58Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![andrey2185](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrey2185/32/9889_2.png) [@andrey2185](https://discourse.julialang.org/u/andrey2185)\
**Post date:** [November 21, 2022, 7:43pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/1 "2022-11-21T19:43:58Z")

</div>

Hello i am trying to speed up this: `x::Bool ^ y::Float64`, and even something come out

Is there any way to avoid branching of f2() in example?

How else to speed up?

```julia
using BenchmarkTools, Test

# simple
f1(x::Bool, y::Float64) = x ^ y;

# faster
function f2(x::Bool, y::Float64)
    if x 
        return 1.0 # true ^ any_float64 -> 1.0
    elseif isnan(y) 
        return NaN # false ^ NaN -> NaN
    elseif y > 0 
        return 0.0
    elseif y < 0 
        return Inf
    else # y == 0
        return 1.0  
    end
end;

# test data
n = 10000;
r = zeros(Float64, n); # for result
x = rand(Bool, n);
y = randn(Float64, n) .^ 111;
y[rand(1:n, 100)] .= NaN;
y[rand(1:n, 100)] .= -Inf;
y[rand(1:n, 100)] .= Inf;
y[rand(1:n, 100)] .= nextfloat(-Inf);
y[rand(1:n, 100)] .= prevfloat(Inf);
y[rand(1:n, 100)] .= 0.0;
y[rand(1:n, 100)] .= -0.0;

#test
@testset begin
    for i = 1 : n
        @test f1(x[i],y[i]) === f2(x[i],y[i])
    end
end;

# benchmarks
f!(f,r,x,y,n) = for i = 1 : n
    r[i] = f(x[i], y[i])
end;

@btime f!($f1,$r,$x,$y,$n) # -> 243.600 μs (0 allocations: 0 bytes)
@btime f!($f2,$r,$x,$y,$n) # -> 5.783 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 21, 2022, 8:11pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/2 "2022-11-21T20:11:38Z")

</div>

You can write this as

```julia
function f3(x::Bool, y::T) where T<:AbstractFloat
    ifelse(x | iszero(y), one(T), abs(y) * T(Inf) * (!(y>0)))
end

```

which on my computer benchmarks a bit faster.

---

<div class="post-metadata">

**Author:** ![andrey2185](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrey2185/32/9889_2.png) [@andrey2185](https://discourse.julialang.org/u/andrey2185)\
**Post date:** [November 21, 2022, 8:14pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/3 "2022-11-21T20:14:28Z")

</div>

cool! thank you

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 21, 2022, 8:16pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/4 "2022-11-21T20:16:15Z")

</div>

If you find a faster way, please make a PR to base for the `Float64^Float64` algorithm.

---

<div class="post-metadata">

**Author:** ![andrey2185](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrey2185/32/9889_2.png) [@andrey2185](https://discourse.julialang.org/u/andrey2185)\
**Post date:** [November 21, 2022, 8:31pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/5 "2022-11-21T20:31:47Z")

</div>

what is the magic of (!(y\>0)) ??  
if (y\<=0) tests fail

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 21, 2022, 8:34pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/6 "2022-11-21T20:34:42Z")

</div>

`NaN>0` and `NaN<0` are both false.

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [November 21, 2022, 11:29pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/7 "2022-11-21T23:29:07Z")

</div>

Out of curiosity, is the purpose of `abs(y)` just to propogate `NaN`, or is there another reason for it?

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 21, 2022, 11:33pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/8 "2022-11-21T23:33:24Z")

</div>

yeah. that was just the cheapest way 8 could find to propagate nan without screwing up anything else

---

<div class="post-metadata">

**Author:** ![andrey2185](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrey2185/32/9889_2.png) [@andrey2185](https://discourse.julialang.org/u/andrey2185)\
**Post date:** [November 25, 2022, 12:39pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/9 "2022-11-25T12:39:37Z")

</div>

Oscar, I found:

```julia
pow_fast(x::Bool, y::T) where T <: AbstractFloat = x ? one(T) : ifelse(iszero(y), one(T), ifelse(isnan(y), T(NaN), ifelse(signbit(y), T(Inf), zero(T))));
pow_fast(x::Bool, y::BigFloat) = x ? big(1.0) : big(ifelse(iszero(y), 1.0 , ifelse(isnan(y), NaN, ifelse(signbit(y), Inf, 0.0))));

pow_fast(x::T, y::Bool) where T <: AbstractFloat = y ? x : one(T);
pow_fast(x::BigFloat, y::Bool) = y ? x : big(1.0); # only big(1.0), not one(x), not BigFloat(1), not one(T)

```

benchmarks, tests:

````julia
module M
	using BenchmarkTools, Test, InteractiveUtils

	println("**", rstrip(Sys.cpu_info()[1].model), "**")
	println(" **Julia-",VERSION,"** \n")

	println("```")

	# 
	pow_native(x::X, y::Y) where {X,Y} = x ^ y

	# 
	pow_fast(x::Bool, y::T) where T <: AbstractFloat = 
		x ? one(T) : ifelse(iszero(y), one(T), ifelse(isnan(y), T(NaN), ifelse(signbit(y), T(Inf), zero(T))));

	pow_fast(x::Bool, y::BigFloat) = 
		x ? big(1.0) : big(ifelse(iszero(y), 1.0 , ifelse(isnan(y), NaN, ifelse(signbit(y), Inf, 0.0))));

	# test data
	function get_test_data1(::Type{T}) where T <: AbstractFloat
		n = 10000
		m = n ÷ 100 # for special values of the same type NaN, -Inf ...
		r = zeros(T, n) # for result
		x = rand(Bool, n)
		#x = ones(Bool, n)
		#x = zeros(Bool, n)
		y = (T <: BigFloat ? big.(randn(Float64, n)) : randn(T, n)) .^ 111
		y[rand(1:n, m)] .= T(NaN)
		y[rand(1:n, m)] .= -T(Inf)
		y[rand(1:n, m)] .= T(Inf)
		y[rand(1:n, m)] .= nextfloat(-T(Inf))
		y[rand(1:n, m)] .= prevfloat(T(Inf))
		y[rand(1:n, m)] .= T(0)
		y[rand(1:n, m)] .= -T(0)
		return n, r, x, y
	end

	# tests
	@testset verbose = true "Tests" begin
		@testset verbose = false "Fast `bool ^ float`" begin
			for Flt in subtypes(AbstractFloat)
				@testset verbose = true " $Flt" begin
					n, r, x, y = get_test_data1(Flt)
					@testset "$pow_fast" begin 
						for i = 1 : n
							r_native = pow_native(x[i],y[i])
							r_fast = pow_fast(x[i],y[i])
							# big(1.0) !== big(1.0), NaN != NaN
							@test r_native == r_fast ? true :  
								isnan(r_native) & isnan(r_fast) ? true : false
						end
					end
				end
			end
		end
	end;

	# benchmarks
	# func
	f!(f,r,x,y,n) = for i = 1 : n
		r[i] = f(x[i], y[i])
	end;

	println("\nFast `bool ^ float` benchmark (1 - native 2 - fast):")

	for Flt in subtypes(AbstractFloat)
		n, r, x, y = get_test_data1(Flt)
		println(" $Flt:")
		@btime f!($pow_native,$r,$x,$y,$n) 
		@btime f!($pow_fast,$r,$x,$y,$n) 
	end

	println("```")

end;

````

---

<div class="post-metadata">

**Author:** ![andrey2185](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrey2185/32/9889_2.png) [@andrey2185](https://discourse.julialang.org/u/andrey2185)\
**Post date:** [November 25, 2022, 1:02pm UTC](https://discourse.julialang.org/t/speed-up-x-bool-y-float64/90601/10 "2022-11-25T13:02:11Z")

</div>

**AMD Ryzen 9 3900XT 12-Core Processor**  
**Julia-1.8.0**

```julia
Test Summary: | Pass Total Time
Tests | 40000 40000 1.3s
  Fast `bool ^ float` | 40000 40000 1.3s

Fast `bool ^ float` benchmark (1 - native 2 - fast):
 BigFloat:
  1.147 ms (40000 allocations: 1.98 MiB)
  770.800 μs (20000 allocations: 1015.62 KiB)
 Float16:
  203.600 μs (0 allocations: 0 bytes)
  13.200 μs (0 allocations: 0 bytes)
 Float32:
  262.100 μs (0 allocations: 0 bytes)
  1.130 μs (0 allocations: 0 bytes)
 Float64:
  247.500 μs (0 allocations: 0 bytes)
  2.111 μs (0 allocations: 0 bytes)

```
