নিম্নলিখিত কোডটি অবশ্যই স্পষ্টতই ভুল। সমস্যা কি?
i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
নিম্নলিখিত কোডটি অবশ্যই স্পষ্টতই ভুল। সমস্যা কি?
i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
উত্তর:
যেহেতু আইইইইই ভাসমান পয়েন্ট গণিতগুলিতে সমস্ত সংখ্যা হুবহু উপস্থাপন করা যায় না (প্রায় সমস্ত কম্পিউটার দশমিক সংখ্যার প্রতিনিধিত্ব করতে এবং তাদের সাথে গণিত করে এমন স্ট্যান্ডার্ড), আপনি সর্বদা আপনার প্রত্যাশাটি পাবেন না। এটি বিশেষত সত্য কারণ কিছু মান যা সাধারণ, সীমাবদ্ধ দশমিক (যেমন ০.০ এবং ০.০৫) কম্পিউটারে ঠিক উপস্থাপন করা হয় না এবং সুতরাং গাণিতিকের ফলাফলগুলি কোনও ফলাফল দিতে পারে না যা প্রত্যক্ষভাবে উপস্থাপনের অনুরূপ " পরিচিত "উত্তর।
এটি কম্পিউটার গাণিতিকের একটি সুপরিচিত সীমাবদ্ধতা এবং এটি বেশ কয়েকটি জায়গায় আলোচনা করা হয়েছে:
এটির মধ্যে স্ট্যান্ডার্ড সমাধানটি 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 এর কাছাকাছি, যেমন এটি।
আর এর মেশিনের ক্ষেত্রটি দেখে এই ক্ষুদ্রতম প্রতিনিধিত্বযোগ্য নম্বরটি আমরা কোনও প্রদত্ত কম্পিউটারের জন্য জানতে পারি :
?.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 ফাংশনটি আসলে পরীক্ষা করছে যে সংখ্যার মধ্যে পার্থক্যটি দুটি ম্যান্টিসাসের মধ্যে ক্ষুদ্রতম পার্থক্যের বর্গমূল।
এই অ্যালগরিদম খুব ছোট সংখ্যার নিকটে ডেনারমালাসের কাছাকাছি কিছুটা মজার হয় তবে আপনাকে সে সম্পর্কে চিন্তা করার দরকার নেই।
উপরের আলোচনাটি দুটি একক মানের একটি তুলনা ধরে নিয়েছে। আর-তে কোনও স্কেলার নেই, কেবল ভেক্টর এবং অন্তর্নিহিত ভেক্টরাইজেশন ভাষার একটি শক্তি a উপাদান অনুসারে ভেক্টরগুলির মান তুলনা করার জন্য, পূর্ববর্তী নীতিগুলি ধারণ করে তবে বাস্তবায়ন কিছুটা আলাদা is ==
ভেক্টরাইজড (একটি উপাদান-ভিত্তিক তুলনা করে) যখন 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
এটি গ্রহণ করা পদ্ধতি dplyr::near
, যা নিজেই দলিল করে
ভাসমান পয়েন্ট সংখ্যার দুটি ভেক্টর (জোড়ের দিকের) সমান হলে এটি তুলনা করার একটি নিরাপদ উপায়। এটি ব্যবহারের চেয়ে নিরাপদ
==
, কারণ এতে সহনশীলতা রয়েছে
dplyr::near(a, b)
#[1] TRUE TRUE TRUE FALSE
ব্রায়ানের মন্তব্যে যুক্ত করা (যা কারণ) এর 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
প্রতি জোশুয়ার সতর্কতাটি এখানে আপডেট কোড (ধন্যবাদ জোশুয়া):
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
all.equal
FALSE
মতপার্থক্য থাকলে ফিরে আসে না , সুতরাং isTRUE
কোনও if
বিবৃতিতে এটি ব্যবহার করার সময় আপনাকে এটি মোড়ানো প্রয়োজন ।
এটি হ্যাকিশ, তবে দ্রুত:
if(round(i, 10)==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
all.equal(... tolerance)
প্যারামিটারটি ব্যবহার করতে পারেন । all.equal(0.147, 0.15, tolerance=0.05)
সত্য.
dplyr::near()
ভাসমান পয়েন্ট সংখ্যার দুটি ভেক্টর সমান হলে পরীক্ষার জন্য একটি বিকল্প। ডক্স থেকে এটি উদাহরণ :
sqrt(2) ^ 2 == 2
#> [1] FALSE
library(dplyr)
near(sqrt(2) ^ 2, 2)
#> [1] TRUE
ফাংশনটিতে সহনশীলতার প্যারামিটারটি অন্তর্নির্মিত রয়েছে: tol = .Machine$double.eps^0.5
যা সামঞ্জস্য করা যায়। ডিফল্ট পরামিতি ডিফল্ট হিসাবে একই all.equal()
।
আমারও একই সমস্যা ছিল। আমি নিম্নলিখিত সমাধানটি ব্যবহার করেছি।
@ আমি এই কাজটি অসম কাটা বিরতি সম্পর্কে সমাধানের আশেপাশে পেয়েছি। @ আমি আর-তে রাউন্ড ফাংশনটি ব্যবহার করেছি 2 বিকল্পে বিকল্পটি সেট করেও সমস্যার সমাধান হয়নি।
options(digits = 2)
cbind(
seq( from = 1, to = 9, by = 1 ),
cut( seq( from = 1, to = 9, by = 1), c( 0, 3, 6, 9 ) ),
seq( from = 0.1, to = 0.9, by = 0.1 ),
cut( seq( from = 0.1, to = 0.9, by = 0.1), c( 0, 0.3, 0.6, 0.9 )),
seq( from = 0.01, to = 0.09, by = 0.01 ),
cut( seq( from = 0.01, to = 0.09, by = 0.01), c( 0, 0.03, 0.06, 0.09 ))
)
বিকল্পের উপর ভিত্তি করে অসম কাটা বিরতির আউটপুট (অঙ্কগুলি = 2):
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 0.1 1 0.01 1
[2,] 2 1 0.2 1 0.02 1
[3,] 3 1 0.3 2 0.03 1
[4,] 4 2 0.4 2 0.04 2
[5,] 5 2 0.5 2 0.05 2
[6,] 6 2 0.6 2 0.06 3
[7,] 7 3 0.7 3 0.07 3
[8,] 8 3 0.8 3 0.08 3
[9,] 9 3 0.9 3 0.09 3
options(digits = 200)
cbind(
seq( from = 1, to = 9, by = 1 ),
cut( round(seq( from = 1, to = 9, by = 1), 2), c( 0, 3, 6, 9 ) ),
seq( from = 0.1, to = 0.9, by = 0.1 ),
cut( round(seq( from = 0.1, to = 0.9, by = 0.1), 2), c( 0, 0.3, 0.6, 0.9 )),
seq( from = 0.01, to = 0.09, by = 0.01 ),
cut( round(seq( from = 0.01, to = 0.09, by = 0.01), 2), c( 0, 0.03, 0.06, 0.09 ))
)
বৃত্তাকার ফাংশনের উপর ভিত্তি করে সমান কাটা বিরতির আউটপুট:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 0.1 1 0.01 1
[2,] 2 1 0.2 1 0.02 1
[3,] 3 1 0.3 1 0.03 1
[4,] 4 2 0.4 2 0.04 2
[5,] 5 2 0.5 2 0.05 2
[6,] 6 2 0.6 2 0.06 2
[7,] 7 3 0.7 3 0.07 3
[8,] 8 3 0.8 3 0.08 3
[9,] 9 3 0.9 3 0.09 3
ডাবল প্রাক্কলিত গাণিতিকের সাধারণ তুলনা ("<=", "> =", "="):
একটি <= বি: তুলনা করা
IsSmallerOrEqual <- function(a,b) {
# Control the existence of "Mean relative difference..." in all.equal;
# if exists, it results in character, not logical:
if ( class(all.equal(a, b)) == "logical" && (a<b | all.equal(a, b))) { return(TRUE)
} else if (a < b) { return(TRUE)
} else { return(FALSE) }
}
IsSmallerOrEqual(abs(-2-(-2.2)), 0.2) # TRUE
IsSmallerOrEqual(abs(-2-(-2.2)), 0.3) # TRUE
IsSmallerOrEqual(abs(-2-(-2.2)), 0.1) # FALSE
IsSmallerOrEqual(3,3); IsSmallerOrEqual(3,4); IsSmallerOrEqual(4,3)
# TRUE; TRUE; FALSE
একটি>> বি তুলনা করা:
IsBiggerOrEqual <- function(a,b) {
# Control the existence of "Mean relative difference..." in all.equal;
# if exists, it results in character, not logical:
if ( class(all.equal(a, b)) == "logical" && (a>b | all.equal(a, b))) { return(TRUE)
} else if (a > b) { return(TRUE)
} else { return(FALSE) }
}
IsBiggerOrEqual(3,3); IsBiggerOrEqual(4,3); IsBiggerOrEqual(3,4)
# TRUE; TRUE; FALSE
A = b এর তুলনা করা:
IsEqual <- function(a,b) {
# Control the existence of "Mean relative difference..." in all.equal;
# if exists, it results in character, not logical:
if ( class(all.equal(a, b)) == "logical" ) { return(TRUE)
} else { return(FALSE) }
}
IsEqual(0.1+0.05,0.15) # TRUE