带有缩放以避免破坏性下溢和溢出的向量的欧几里得长度(k-范数)的答案是
norm <- function(x, k) { max(abs(x))*(sum((abs(x)/max(abs(x)))^k))^(1/k) }
请参阅下面的说明。
1. 没有缩放的向量的欧几里得长度:
norm()
是一个向量值函数,它计算向量的长度。它需要两个参数,例如 class 的向量x
和 classmatrix
的范数k
类型integer
。
norm <- function(x, k) {
# x = matrix with column vector and with dimensions mx1 or mxn
# k = type of norm with integer from 1 to +Inf
stopifnot(k >= 1) # check for the integer value of k greater than 0
stopifnot(length(k) == 1) # check for length of k to be 1. The variable k is not vectorized.
if(k == Inf) {
# infinity norm
return(apply(x, 2, function(vec) max(abs(vec)) ))
} else {
# k-norm
return(apply(x, 2, function(vec) (sum((abs(vec))^k))^(1/k) ))
}
}
x <- matrix(c(1,-2,3,-4)) # column matrix
sapply(c(1:4, Inf), function(k) norm(x = x, k = k))
# [1] 10.000000 5.477226 4.641589 4.337613 4.000000
- 1 范数 (10.0) 收敛到无穷范数 (4.0)。
- k-norm 也称为“欧几里得 n 维空间中的欧几里得范数”。
注意:
在norm()
函数定义中,对于具有实分量的向量,绝对值可以在 norm-2k 甚至索引范数中删除,其中k >= 1
.
如果您对norm
函数定义感到困惑,您可以单独阅读下面给出的每一个。
norm_1 <- function(x) sum(abs(x))
norm_2 <- function(x) (sum((abs(x))^2))^(1/2)
norm_3 <- function(x) (sum((abs(x))^3))^(1/3)
norm_4 <- function(x) (sum((abs(x))^4))^(1/4)
norm_k <- function(x) (sum((abs(x))^k))^(1/k)
norm_inf <- max(abs(x))
2. 带有缩放的向量的欧几里得长度以避免破坏性的上溢和下溢问题:
注2:
这个解决方案的唯一问题norm()
是它不能防止这里和这里提到的溢出或下溢问题。
幸运的是,有人已经在 blas(基本线性代数子程序)fortran 库中解决了 2 范数(欧几里得长度)的问题。可以在“Kahaner、Moler 和 Nash 的数值方法和软件”教科书 - 第 1 章,第 1.3 节,第 7-9 页中找到对这个问题的描述。
fortran 子例程的名称是,它通过缩放向量分量的最大值来dnrm2.f
处理破坏性上溢和下溢问题。norm()
由于norm()
函数中的激进操作,会出现破坏性上溢和下溢问题。
dnrm2.f
我将在R
下面展示如何实现。
#1. find the maximum among components of vector-x
max_x <- max(x)
#2. scale or divide the components of vector by max_x
scaled_x <- x/max_x
#3. take square of the scaled vector-x
sq_scaled_x <- (scaled_x)^2
#4. sum the square of scaled vector-x
sum_sq_scaled_x <- sum(sq_scaled_x)
#5. take square root of sum_sq_scaled_x
rt_sum_sq_scaled_x <- sqrt(sum_sq_scaled_x)
#6. multiply the maximum of vector x with rt_sum_sq_scaled_x
max_x*rt_sum_sq_scaled_x
dnrm2.f
上述6个步骤的单行R
是:
# Euclidean length of vector - 2norm
max(x)*sqrt(sum((x/max(x))^2))
让我们尝试示例向量来计算此问题的 2 范数(请参阅此线程中的其他解决方案)。
x = c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299)
max(x)*sqrt(sum((x/max(x))^2))
# [1] 1.227355e+300
x <- (c(1,-2,3,-4))
max(x)*sqrt(sum((x/max(x))^2))
# [1] 5.477226
因此,在 R 中实现 k 范数的通用解决方案的推荐方法是单行,它可以防止破坏性上溢或下溢问题。为了改进这种单线,您可以norm()
对包含不太小或不太大的分量knorm()
的向量使用不缩放和对分量过小或太大的向量进行缩放的组合。对所有向量实施缩放会导致计算量过多。我没有在knorm()
下面给出这个改进。
# one-liner for k-norm - generalized form for all norms including infinity-norm:
max(abs(x))*(sum((abs(x)/max(abs(x)))^k))^(1/k)
# knorm() function using the above one-liner.
knorm <- function(x, k) {
# x = matrix with column vector and with dimensions mx1 or mxn
# k = type of norm with integer from 1 to +Inf
stopifnot(k >= 1) # check for the integer value of k greater than 0
stopifnot(length(k) == 1) # check for length of k to be 1. The variable k is not vectorized.
# covert elements of matrix to its absolute values
x <- abs(x)
if(k == Inf) { # infinity-norm
return(apply(x, 2, function(vec) max(vec)))
} else { # k-norm
return(apply(x, 2, function(vec) {
max_vec <- max(vec)
return(max_vec*(sum((vec/max_vec)^k))^(1/k))
}))
}
}
# 2-norm
x <- matrix(c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299))
sapply(2, function(k) knorm(x = x, k = k))
# [1] 1.227355e+300
# 1-norm, 2-norm, 3-norm, 4-norm, and infinity-norm
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
# [1] 2.480000e+300 1.227355e+300 9.927854e+299 9.027789e+299 8.000000e+299
x <- matrix(c(1,-2,3,-4))
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
# [1] 10.000000 5.477226 4.641589 4.337613 4.000000
x <- matrix(c(1,-2,3,-4, 0, -8e+299, -6e+299, 5e+299, -8e+298, -5e+299), nc = 2)
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1.00e+01 5.477226e+00 4.641589e+00 4.337613e+00 4e+00
# [2,] 2.48e+300 1.227355e+300 9.927854e+299 9.027789e+299 8e+299