Round and signif и merge data.table проблема неправильного объединения [duplicate]

Просто используйте оболочку div с «float: left» и поместите поля внутри, также содержащие float: left:

CSS:

wrapperline{
width: 300px;
float: left;
height: 60px;
background-color:#CCCCCC;}

.boxinside{
width: 50px;
float: left;
height: 50px;
margin: 5px;
background-color:#9C0;
float:left;}

HTML:

<div class="wrapperline">
<div class="boxinside">Box 1</div>
<div class="boxinside">Box 1</div>
<div class="boxinside">Box 1</div>
<div class="boxinside">Box 1</div>
<div class="boxinside">Box 1</div>
</div>
219
задан Jaap 30 May 2018 в 19:56
поделиться

3 ответа

Основная (языковая агностическая) причина

Поскольку не все числа могут быть представлены точно в IEEE с плавающей точкой арифметики (стандарт, который почти все компьютеры используют для представления десятичных чисел и делают математика с ними), вы не всегда получите то, что ожидаете. Это особенно верно, потому что некоторые значения, которые являются простыми, конечными десятичными знаками (такими как 0,1 и 0,05), не представлены точно в компьютере, и поэтому результаты арифметики на них могут не дать результата, который идентичен прямому представлению " (g30) Это хорошо известное ограничение компьютерной арифметики и обсуждается в нескольких местах:

Сравнение скаляров

Стандартное решение этого в R не должно использовать == , а скорее функцию all.equal . Вернее, поскольку all.equal дает много подробностей о различиях, если они есть, isTRUE(all.equal(...)).

if(isTRUE(all.equal(i,0.15))) cat("i equals 0.15") else cat("i does not equal 0.15")

дает

i equals 0.15

. Еще несколько примеров использования all.equal вместо == (последний пример должен показать, что это будет правильно отображать различия).

0.1+0.05==0.15
#[1] FALSE
isTRUE(all.equal(0.1+0.05, 0.15))
#[1] TRUE
1-0.1-0.1-0.1==0.7
#[1] FALSE
isTRUE(all.equal(1-0.1-0.1-0.1, 0.7))
#[1] TRUE
0.3/0.1 == 3
#[1] FALSE
isTRUE(all.equal(0.3/0.1, 3))
#[1] TRUE
0.1+0.1==0.15
#[1] FALSE
isTRUE(all.equal(0.1+0.1, 0.15))
#[1] FALSE

Более подробная информация, непосредственно скопированная из ответа на аналогичный вопрос :

Проблема, с которой вы столкнулись, заключается в том, что в большинстве случаев плавающая точка не может представлять десятичные дроби, что означает, что вы часто обнаруживаете, что точные совпадения не срабатывают.

немного, когда вы говорите:

1.1-0.2
#[1] 0.9
0.9
#[1] 0.9

Вы можете узнать, что он на самом деле думает в десятичной форме:

sprintf("%.54f",1.1-0.2)
#[1] "0.900000000000000133226762955018784850835800170898437500"
sprintf("%.54f",0.9)
#[1] "0.900000000000000022204460492503130808472633361816406250"

Вы можете видеть, что эти цифры разные, но представление немного громоздкий. Если мы посмотрим на них в двоичном (ну, шестнадцатеричный, что эквивалентно), мы получим более четкое изображение:

sprintf("%a",0.9)
#[1] "0x1.ccccccccccccdp-1"
sprintf("%a",1.1-0.2)
#[1] "0x1.ccccccccccccep-1"
sprintf("%a",1.1-0.2-0.9)
#[1] "0x1p-53"

Вы можете видеть, что они отличаются 2^-53, что важно, потому что это число наименьшая представимая разница между двумя числами, значение которых близко к 1.

Мы можем узнать для любого данного компьютера, что это наименьшее представимое число, просматривая машину R :

 ?.Machine
 #....
 #double.eps     the smallest positive floating-point number x 
 #such that 1 + x != 1. It equals base^ulp.digits if either 
 #base is 2 or rounding is 0; otherwise, it is 
 #(base^ulp.digits) / 2. Normally 2.220446e-16.
 #....
 .Machine$double.eps
 #[1] 2.220446e-16
 sprintf("%a",.Machine$double.eps)
 #[1] "0x1p-52"

Вы можете использовать этот факт для создания функции «почти равных», которая проверяет, что разница близка к наименьшему представимому числу в плавающей запятой. На самом деле это уже существует: all.equal.

?all.equal
#....
#all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
#....
#all.equal(target, current,
#      tolerance = .Machine$double.eps ^ 0.5,
#      scale = NULL, check.attributes = TRUE, ...)
#....

Таким образом, функция all.equal фактически проверяет, что разница между числами является квадратным корнем из наименьшей разницы между двумя мантиссами.

Этот алгоритм немного смешен рядом с чрезвычайно маленькими числами, называемыми денормалами, но вам не нужно об этом беспокоиться.

Сравнение векторов

Вышеприведенное обсуждение предполагало сравнение двух отдельных значений. В R нет скаляров, просто векторы и неявная векторизация - сила языка. Для сравнения значений векторов по-прежнему соблюдаются предыдущие принципы, но реализация несколько отличается. == векторизован (имеет элементное сравнение), а all.equal сравнивает целые векторы как единый объект.

Используя предыдущие примеры

a <- c(0.1+0.05, 1-0.1-0.1-0.1, 0.3/0.1, 0.1+0.1)
b <- c(0.15,     0.7,           3,       0.15)

== не дает «ожидаемого» результата, а all.equal не выполняет элементарные

a==b
#[1] FALSE FALSE FALSE FALSE
all.equal(a,b)
#[1] "Mean relative difference: 0.01234568"
isTRUE(all.equal(a,b))
#[1] FALSE

Скорее, следует использовать версию, которая пересекает два вектора

mapply(function(x, y) {isTRUE(all.equal(x, y))}, a, b)
#[1]  TRUE  TRUE  TRUE FALSE

Если требуется функциональная версия, это можно записать

elementwise.all.equal <- Vectorize(function(x, y) {isTRUE(all.equal(x, y))})

, который можно назвать только

elementwise.all.equal(a, b)
#[1]  TRUE  TRUE  TRUE FALSE

. Вместо этого вместо обертывания all.equal в четном больше вызовов функций, вы можете просто воспроизвести соответствующие внутренние элементы all.equal.numeric и использовать неявную векторию:

tolerance = .Machine$double.eps^0.5
# this is the default tolerance used in all.equal,
# but you can pick a different tolerance to match your needs

abs(a - b) < tolerance
#[1]  TRUE  TRUE  TRUE FALSE
291
ответ дан 13 revs, 5 users 66% 17 August 2018 в 08:52
поделиться

Это хакерский, но быстрый:

if(round(i, 10)==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
9
ответ дан Hillary Sanders 17 August 2018 в 08:52
поделиться
  • 1
    Но вы можете использовать параметр all.equal(... tolerance). all.equal(0.147, 0.15, tolerance=0.05) имеет значение ИСТИНА. – smci 28 May 2018 в 11:25

Добавляя к комментарию Брайана (по этой причине), вы можете это сделать, используя all.equal вместо этого:

# i <- 0.1
# i <- i + 0.05
# i
#if(all.equal(i, .15)) cat("i equals 0.15\n") else cat("i does not equal 0.15\n")
#i equals 0.15

Предупреждение от Joshua здесь - это обновленный код (спасибо Джошуа):

 i <- 0.1
 i <- i + 0.05
 i
if(isTRUE(all.equal(i, .15))) { #code was getting sloppy &went to multiple lines
    cat("i equals 0.15\n") 
} else {
    cat("i does not equal 0.15\n")
}
#i equals 0.15
34
ответ дан Tyler Rinker 17 August 2018 в 08:52
поделиться
  • 1
    Я пропустил ссылку Брайана, которая объясняет мой ответ лаконично. – Tyler Rinker 1 March 2012 в 01:57
  • 2
    all.equal не возвращает FALSE, когда есть различия, поэтому вам нужно обернуть его с помощью isTRUE при использовании в инструкции if. – Joshua Ulrich 1 March 2012 в 02:49
Другие вопросы по тегам:

Похожие вопросы: