Skip to content

Commit e08d979

Browse files
committed
Implement normalize and normalize!
Simple helper functions for normalizing vectors Closes #12047
1 parent e60d546 commit e08d979

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

base/exports.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,8 @@ export
676676
lufact,
677677
lyap,
678678
norm,
679+
normalize,
680+
normalize!,
679681
nullspace,
680682
ordschur!,
681683
ordschur,

base/linalg.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ export
9595
lufact!,
9696
lyap,
9797
norm,
98+
normalize,
99+
normalize!,
98100
nullspace,
99101
ordschur!,
100102
ordschur,

base/linalg/generic.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,3 +529,68 @@ function isapprox{T<:Number,S<:Number}(x::AbstractArray{T}, y::AbstractArray{S};
529529
d = norm(x - y)
530530
return isfinite(d) ? d <= atol + rtol*max(norm(x), norm(y)) : x == y
531531
end
532+
533+
"""
534+
normalize!(v, [p=2])
535+
536+
Normalize the vector `v` in-place with respect to the `p`-norm.
537+
538+
# Inputs
539+
540+
- `v::AbstractVector` - vector to be normalized
541+
- `p::Real` - The `p`-norm to normalize with respect to. Default: 2
542+
543+
# Output
544+
545+
- `v` - A unit vector being the input vector, rescaled to have norm 1.
546+
The input vector is modified in-place.
547+
548+
# See also
549+
550+
`normalize`
551+
552+
"""
553+
function normalize!(v::AbstractVector, p::Real=2)
554+
nrm = norm(v, p)
555+
556+
#The largest positive floating point number whose inverse is less than
557+
#infinity
558+
const δ = inv(prevfloat(typemax(float(nrm))))
559+
560+
if nrm δ #Safe to multiply with inverse
561+
invnrm = inv(nrm)
562+
scale!(v, invrm)
563+
564+
else #Divide by norm; slower but more correct
565+
#Note 2015-10-19: As of Julia 0.4, @simd does not vectorize floating
566+
#point division, although vectorized intrinsics like DIVPD exist. I
567+
#will leave the @simd annotation in, hoping that someone will improve
568+
#the @simd macro in the future. - cjh
569+
@inbounds @simd for i in eachindex(v)
570+
v[i] /= nrm
571+
end
572+
end
573+
574+
v
575+
end
576+
577+
"""
578+
normalize(v, [p=2])
579+
580+
Normalize the vector `v` with respect to the `p`-norm.
581+
582+
# Inputs
583+
584+
- `v::AbstractVector` - vector to be normalized
585+
- `p::Real` - The `p`-norm to normalize with respect to. Default: 2
586+
587+
# Output
588+
589+
- `v` - A unit vector being a copy of the input vector, scaled to have norm 1
590+
591+
# See also
592+
593+
`normalize!`
594+
"""
595+
normalize(v::AbstractVector, p::Real=2) = v/norm(v, p)
596+

test/linalg/generic.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,24 @@ let
150150
@test LinAlg.axpy!(α, x, deepcopy(y)) == x .* Matrix{Int}[α]
151151
@test LinAlg.axpy!(α, x, deepcopy(y)) != Matrix{Int}[α] .* x
152152
end
153+
154+
let
155+
v = [3.0, 4.0]
156+
@test norm(v) === 5.0
157+
w = normalize(v)
158+
@test w == [0.6, 0.8]
159+
@test norm(w) === 1.0
160+
@test normalize!(v) == w
161+
end
162+
163+
#Test potential overflow in normalize!
164+
let
165+
δ = inv(prevfloat(typemax(float(nrm))))
166+
v = [δ, -δ]
167+
168+
@test norm(v) === 7.866824069956793e-309
169+
w = normalize(v)
170+
@test norm(w) === 1.0
171+
@test w [1/√2, -1/√2]
172+
@test normalize!(v) == w
173+
end

0 commit comments

Comments
 (0)