Trying to implement a combination of 4 objects taken 2 at a time without taking into account the arrangement (such must be considered duplicates: so that order is not important) of objects with std::set container:
struct Combination {
int m;
int n;
Combination(const int m, const int n):m(m),n(n){}
};
const auto operator<(const auto & a, const auto & b) {
//explicitly "telling" that order should not matter:
if ( a.m == b.n && a.n == b.m ) return false;
//the case "a.m == b.m && a.n == b.n" will result in false here too:
return a.m == b.m ? a.n < b.n : a.m < b.m;
}
#include <set>
#include <iostream>
int main() {
std::set< Combination > c;
for ( short m = 0; m < 4; ++ m ) {
for ( short n = 0; n < 4; ++ n ) {
if ( n == m ) continue;
c.emplace( m, n );
} }
std::cout << c.size() << std::endl; //12 (but must be 6)
}
The expected set of combinations is 0 1, 0 2, 0 3, 1 2, 1 3, 2 3 which is 6 of those, but resulting c.size() == 12. Also, my operator<(Combination,Combination) does satisfy !comp(a, b) && !comp(b, a) means elements are equal requirement.
What am I missing?
Your code can't work1, because your operator< does not introduce a strict total ordering. One requirement for a strict total ordering is that, for any three elements a, b and c
a < b
and
b < c
imply that
a < c
(in a mathematical sense). Let's check that. If we take
Combination a(1, 3);
Combination b(1, 4);
Combination c(3, 1);
you see that
a < b => true
b < c => true
but
a < c => false
If you can't order the elements you can't use std::set. A std::unordered_set seems to more suited for the task. You just need a operator== to compare for equality, which is trivial and a hash function that returns the same value for elements that are considere identical. It could be as simple as adding m and n.
1 Well, maybe it could work, or not, or both, it's undefined behaviour.
Attached is the working code. The tricky part that you were missing was not adding a section of code to iterate through the already working set to then check the values. You were close! If you need a more thorough answer I will answer questions in the comments. Hope this helps!
#include <set>
#include <iostream>
using namespace std;
struct Combination {
int m;
int n;
Combination(const int m, const int n):m(m),n(n){}
};
const auto operator<(const auto & a, const auto & b) {
//explicitly "telling" that order should not matter:
if ( a.m == b.n && a.n == b.m ) return false;
//the case "a.m == b.m && a.n == b.n" will result in false here too:
return a.m == b.m ? a.n < b.n : a.m < b.m;
}
int main() {
set< Combination > c;
for ( short m = 0; m < 4; ++ m )
{
for ( short n = 0; n < 4; ++ n )
{
//Values are the same we do not add to the set
if(m == n){
continue;
}
else{
Combination s(n,m);
const bool is_in = c.find(s) != c.end();
if(is_in == true){
continue;
}
else{
cout << " M: " << m << " N: " << n << endl;
c.emplace( m, n);
}
}
}
}
cout << c.size() << endl; //16 (but must be 6)
}
Related
Lets say I have range of integers [l, r) and a function check(int idx) which satisfies the following condition:
there is an index t (l <= t < r) such that for each i (l <= i <= t) check(i) == true and for each j (t < j < r) check(j) == false. Is there a standard way to find index t?
Standard binary_search() needs comparator that takes two arguments, so it can't be applied here (correct me if I'm wrong).
Assuming you are searching for a continuous range of integers (and not, for example, an indexed array) I would suggest a dichotomic search:
int find_t(int l, int r) {
// Preconditions
assert(check(l) == true);
//assert(check(r) == false); // this precondition is not mandatory
int max_idx_true = l; // highest known integer which satisfies check(idx) == true
int min_idx_false = r; // lowest known integer which satisfies check(idx) == false
while (max_idx_true+1 < min_idx_false) {
int mid_idx = (max_idx_true+min_idx_false)/2;
if (check(mid_idx)) max_idx_true = mid_idx;
else min_idx_false = mid_idx;
}
int t = max_idx_true;
// Postconditions
assert(check(t) == true);
assert(t+1 == r || check(t+1) == false);
return t;
}
This algorithm narrows the closest integers where check(idx) is true and the next one is false. In your case, you are looking for t which corresponds to max_idx_true.
It should be noted that the following preconditions must be satisfied for this to work:
l < r
check(l) is true
for any idx, if check(idx) is true then check(idx-1) is always true
for any idx, if check(idx) is false then check(idx+1) is always false
Below is a source code example for testing the algorithm and output lines to better understand how it works. You can also try it out here.
#include <iostream>
#include <cassert>
using namespace std;
// Replace this function by your own check
bool check(int idx) {
return idx <= 42;
}
int find_t(int l, int r) {
assert(check(l) == true);
//assert(check(r) == false); // this precondition is not mandatory
int max_idx_true = l; // highest known integer which satisfies check(idx) == true
int min_idx_false = r; // lowest known integer which satisfies check(idx) == false
int n = 0; // Number of iterations, not needed but helps analyzing the complexity
while (max_idx_true+1 < min_idx_false) {
++n;
int mid_idx = (max_idx_true+min_idx_false)/2;
// Analyze the algorithm in detail
cerr << "Iteration #" << n;
cerr << " in range [" << max_idx_true << ", " << min_idx_false << ")";
cerr << " the midpoint " << mid_idx << " is " << boolalpha << check(mid_idx) << noboolalpha;
cerr << endl;
if (check(mid_idx)) max_idx_true = mid_idx;
else min_idx_false = mid_idx;
}
int t = max_idx_true;
assert(check(t) == true);
assert(t+1 == r || check(t+1) == false);
return t;
}
int main() {
// Initial constants
int l = 0;
int r = 100;
int t = find_t(l, r);
cout << "The answer is " << t << endl;
return 0;
}
The main advantage of the dichomotic search is that it finds your candidate with a complexity of only O(log2(N)).
For example if you initialize int l = -2000000000 and int r = 2000000000 (+/- 2 billions) you need to known the answer in about 4 billion numbers, yet the number of iterations will be 32 at worst.
Here is a sample Raku code which uses a grep closure with a sample criteria consisting of a function and logical operators:
print "$_, " for ( grep { is-prime $_ and $_ > 5 and not ($_ == 11 or $_ == 13) }, 1..20);
# Output is: 7, 17, 19
I'd like to port this into C++ using a vector or a list and a lambda in which I can set the sample criteria. Here's my take:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;
bool isPrime(int num){
bool flag=true;
for(int i = 2; i <= num / 2; i++) {
if(num % i == 0) {
flag = false;
break; } }
return flag;}
int main(){
vector<int> a(20);
iota(begin(a), end(a), 1);
vector<int> b(a.size());
auto end = copy_if(cbegin(a), cend(a), begin(b),
[](int x) { return isPrime(x) & ( x > 5 ) & !( (x == 11) | (x == 13) ); });
b.erase(end, b.end());
for (auto n: b)
cout << n << '\n';
// Output is: 7, 17, 19
}
I'm trying yo make it without using copy_if i.e. by using find_if so that I don't have to create the auxiliary vector b Here is my take:
for (auto x : a) cout << find_if(a.begin(), a.end(), [x](){return isPrime(x) & ( x > 5 ) & !( (x == 11) | (x == 13));});
But it doesn't work. How to do it?
What Perl calls grep here is called a filter in C++ (and some other contexts). C++20 offers std::ranges::filter_view for the purpose, but since this question is tagged for C++17…
The find_if approach you tried doesn't make sense because it still involves iterating over every element (and asks the library to search with a "predicate" that takes no arguments).
It's certainly possible to use std::find_if to advance an iterator to each new value of interest in turn:
for(auto i=a.begin(),e=a.end();i!=e;
i=find_if(i+1,e,[](int x)
{return isPrime(x) & ( x > 5 ) && !( (x == 11) || (x == 13));})
cout << n << '\n';
(Note the logical instead of bitwise operators.) Since this involves an explicit loop (to keep track of the start position for each search) it's no better than the purely imperative approach of considering every element:
for(auto n : a)
if(isPrime(x) && ( x > 5 ) && !( (x == 11) || (x == 13) ))
cout << n << '\n';
Perhaps the most natural approach to avoiding the copy prior to C++20 is to use std::copy_if but with a stream iterator as the output "sequence":
copy_if(cbegin(a), cend(a), std::ostream_iterator<int>(std::cout, "\n"),
[](int x) { return isPrime(x) && ( x > 5 ) && !( (x == 11) || (x == 13) ); });
Prior to C++20, there isn't a std equivalent of 1..20 usable with for ( : ), you would instead use for (;;).
auto criteria = [](int x){ return isPrime(x) && (x > 5) && (x != 11) && (x != 13); };
for (int x = 1; x <= 20; ++x) {
if (criteria(x)) {
std::cout << x;
}
}
heyall, just going through some textbook examples for my introductory c++ course and I would really appreciate it if somebody could clarify why the following code produces an output of 51 (I would expect it to not produce any output whatsoever), many thanks!:
#include <iostream>
using namespace std;
int main()
{
constexpr int a{9};
constexpr int b{1};
constexpr int c{5};
if (a < b < c)
if (c > b > a)
if (a > c) cout << 91;
else cout << 19;
else
if (b < c) cout << 51;
else cout << 15;
else
if (b < a < c)
if (a < c) cout << 95;
else cout << 59;
else
if (b < c) cout << 57;
else cout << 75;
return 0;
}
It seems you expect this expression:
if (a < b < c)
to be true if a, b, and c are in increasing order. But what actually happens is the expression becomes:
if ((a < b) < c)
which is either:
if (0 < c)
// or
if (1 < c)
Either way, that's probably not what you want. In fact, there's no good reason to ever write the above expression.
If you want to check whether the variables are increasing, you need to write something like:
if (a < b && b < c)
In c++, comparisons like 'X<=Y<=Z' do not have their mathematical meaning without parentheses. So, in
if (a < b < c)
we are getting
a < b => 9 < 1 => 0
'0' means the condition is false, which with 'c' is returning
0 < 5 => 1
"1" being returned means that the if condition is True.
Similarly, you can check for the nested if-else loops.
I tried to write a program that receive from the user 5 integers and print the second minimum number.
Here is a sample of what I've tried:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
if (a>b && a<c && a<d && a<e)
cout<<a<<endl;
if (b>a && b<c && b<d && b<e)
cout<<b<<endl;
if (c>a && c<b && c<d && c<e)
cout<<c<<endl;
if (d>a && d<b && d<c && d<e)
cout <<d<<endl;
if (e>a && e<b && e<c && e<d)
cout <<e<<endl;
return 0;
}
When I enter 1 2 3 4 5 it prints the second minimum, but when I enter
5 4 3 2 1 Nothing will print on the screen. What am I doing wrong with this? Is there any other way to write my program?
The problem you have with your logic is that you do not enforce yourself to print only 1 item, and at least one item.
By using the 'else' part of the if/else syntax, you will ensure that only one branch can ever be hit. You can then follow this up with just an else at the end, as you know all other conditions are false.
Once you've done this, you'll see that you print the last value, (1) rather than the expected (4). This is because your logic regarding how to find the 2nd lowest is wrong. b>a is false for the case 5,4...
Note:
Every employed engineer, ever, would make this a loop in a std::vector / std::array, and I would suggest you point your teacher to this post because encouraging loops is a good thing rather than bad.
Something like
vector<int> data;
for (int i=0; i<5; ++i) {
int t;
cin >> t;
data.push_back(t);
}
std::nth_element(data.begin(), data.begin()+1, data.end(), std::greater<int>());
cout << data[1];
There are 120 possible permutations on 5 elements. Your code should output the correct number for all of them. So a fool-proof code would use 120 repetitions of a check, like the following:
if (a > b && b > c && c > d && d > e) // the order is a>b>c>d>e
cout << d;
else if (a > b && b > c && c > e && e > d) // the order is a>b>c>e>d
cout << e;
...
else if (e > d && d > c && c > a && e > b) // the order is e>d>c>a>b
cout << a;
else // the order is e>d>c>b>a
cout << b;
This is very long, inefficient and tricky code. If you do a typo in just one variable, it will output a wrong answer in some rare cases. Also, it doesn't handle the possibility of some inputs being equal.
If the number of inputs to a sorting algorithm is a known small constant, you can use an approach called sorting networks. This is a well-defined computer science problem, which has well-known optimal solutions for small numbers of inputs, and 5 certainly is small. An optimal sorting network for 5 inputs contains 9 comparators, and is described e.g. here.
Since you don't need to sort the numbers, but only to know the second smallest input, you can reduce the size of the network further, to 7 comparators.
The full sorting network (without the reduction from 9 to 7) translated to C++:
if (b < c)
swap(b, c);
if (d < e)
swap(d, e);
if (b < d)
swap(b, d);
if (a < c)
swap(a, c);
if (c < e)
swap(c, e);
if (a < d)
swap(a, d);
if (a < b)
swap(a, b);
if (c < d)
swap(c, d);
if (b < c)
swap(b, c);
// now the order is a ≥ b ≥ c ≥ d ≥ e
cout << d;
This code is also obscure - not obvious at all how and why it works - but at least it is small and in a sense optimal. Also, it's clear that it always prints something (so it fixes the original problem) and supports the case of partially equal inputs.
If you ever use such code in a larger project, you should document where you took it from, and test it. Fortunately, there are exactly 120 different possibilities (or 32, if you use the
zero-one principle), so there is a way to prove that this code has no bugs.
This should work for you. (Note that it might not be the best approach and you can minimize it with a function to calculate min and secondMin instead of the ugly copy paste of the logic but it will get you started:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
int min, secondMin;
cin>>a>>b;
min = a < b ? a : b;
secondMin = a < b ? b : a;
cin>>c;
if (c < min)
{
secondMin = min;
min = c;
}
else if (c < secondMin)
{
secondMin = c;
}
cin>>d;
if (d < min)
{
secondMin = min;
min = d;
}
else if (c < secondMin)
{
secondMin = d;
}
cin>>e;
if (e < min)
{
secondMin = min;
min = e;
}
else if (e < secondMin)
{
secondMin = e;
}
cout << "min = " << min << ", secondMin = " << secondMin << endl;
return 0;
}
if you have any questions feel free to ask in the comment
#include <set>
std::set<int> values = { a, b, c, d, e }; // not an array.
int second_min = *std::next(values.begin(), 1); // not a loop
What about a recursive and more generic approach?
No arrays, no loops and not limited to just 5 integers.
The following function get_2nd_min() keeps track of the two lowest integers read from std::cin a total of count times:
#include <climits>
#include <cstddef>
#include <iostream>
int get_2nd_min(size_t count, int min = INT_MAX, int second_min = INT_MAX)
{
if (!count)
return second_min; // end of recursion
// read next value from cin
int value;
std::cin >> value;
// Does second_min need to be updated?
if (value < second_min) {
// Does min also need to be updated?
if (value < min) {
// new min found
second_min = min; // move the so far min to second_min
min = value; // update the new min
} else {
// value is lower than second_min but higher than min
second_min = value; // new second_min found, update it
}
}
// perform recursion
return get_2nd_min(count - 1, min, second_min);
}
In order to read 5 integers and obtain the 2nd lowest:
int second_min = get_2nd_min(5);
One approach is to first find the minimum number, min and then find the smallest value that isn't min. To do this first find the minimum value:
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
Now we need to do the same again, but ignoring min. We can do this using a function called triMin which takes 3 values and discards any value that is the minimum:
int triMin(int currentMin, int left, int right)
{
if(currentMin == left) return right;
if(currentMin == right) return left;
return std::min(left, right);
}
You can now combine them to get the answer:
int a = 5, b = 4, c = 3, d = 2, e = 1;
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
int min2 = triMin(min, a, triMin(min, b, triMin(min, c, triMin(min, d, e))));
std::cout << "Second min = " << min2 << std::endl;
This prints 2
This task can be fulfilled using one-pass algorithm. There is no need to use any collections (arrays, sets or anything).
This one-pass algorithm is memory efficient - it does not require storing all elements in collection (and wasting memory) and will work even with large number of elements when other solutions fail with out of memory.
General idea of this algorithm is like this:
take each number in order
you need two variables to store minimum and second minimum numbers from all already seen numbers.
when you get number you need to test it with current minumum to find if it is new minimum number.
if it is store it as minimum, store old minimum in second minimumnumber
otherwise check if it is less than second minimum number.
if it is store it as second minimum number.
now second minimum number contains answer for all already seen numbers.
repeat while there numbers that was not seen.
After investigating all numbers second minimum contain the answer.
Here is implementation with c++17 (link to wandbox):
#include <iostream>
#include <optional>
int main()
{
int a, b, c, d, e;
std::cin >> a >> b >> c >> d >> e;
// you can find second minimal number while going through each number once
auto find_current_answer = [minimum = std::optional<int>{}, next_to_minimum = std::optional<int>{}](int next) mutable {
// when receiving next number
// 1. check if it is new minimum
if (!minimum || minimum > next) {
// move values like this: next_to_minimum <- minimum <- next
next_to_minimum = std::exchange(minimum, next);
}
// 2. else check if it is new next_to_minimum
else if (!next_to_minimum || next_to_minimum > next) {
next_to_minimum = next;
}
// 3. return current answer
return next_to_minimum;
};
// repeat as much as you like
find_current_answer(a);
find_current_answer(b);
find_current_answer(c);
find_current_answer(d);
// store answer that is interesting to you
auto result = find_current_answer(e);
// if it has value - it is the answer
if (result) {
std::cout << "Answer: " << *result << '\n';
}
else {
std::cout << "Not enough numbers!\n";
}
}
Update
In this solution I'm using the min function:
#include <iostream>
using namespace std;
int minDifferentFromFirstMin(int x, int y, int firstMin) {
if(x < y) {
if(x != firstMin) {
return x;
}
else {
return y;
}
}
if(y < x) {
if(y != firstMin) {
return y;
}
else {
return x;
}
}
//if x & y are equals, return one of them
return x;
}
int main () {
int a,b,c,d,e;
int iter11, iter12, iter13;
int iter21, iter22, iter23;
int firstMinimum, secondMinimum;
cin>>a>>b>>c>>d>>e;
//iteration 1: find the first minimum
iter11 = min(a, b);
iter12 = min(c, d);
iter13 = min(iter11, iter12);
firstMinimum = min(iter13, e);
//iteration 2: find the second minimum
iter21 = minDifferentFromFirstMin(a, b, firstMinimum);
iter22 = minDifferentFromFirstMin(c, d, firstMinimum);
iter23 = minDifferentFromFirstMin(iter21, iter22, firstMinimum);
secondMinimum = minDifferentFromFirstMin(iter23, e, firstMinimum);
cout<<secondMinimum<<endl;
}
Is there a good and fast way in C/C++ to test if multiple variables contains either all positive or all negative values?
Say there a 5 variables to test:
Variant 1
int test(int a[5]) {
if (a[0] < 0 && a[1] < 0 && a[2] < 0 && a[3] < 0 && a[4] < 0) {
return -1;
} else if (a[0] > 0 && a[1] > 0 && a[2] > 0 && a[3] > 0 && a[4] > 0) {
return 1;
} else {
return 0;
}
}
Variant 2
int test(int a[5]) {
unsigned int mask = 0;
mask |= (a[0] >> numeric_limits<int>::digits) << 1;
mask |= (a[1] >> numeric_limits<int>::digits) << 2;
mask |= (a[2] >> numeric_limits<int>::digits) << 3;
mask |= (a[3] >> numeric_limits<int>::digits) << 4;
mask |= (a[4] >> numeric_limits<int>::digits) << 5;
if (mask == 0) {
return 1;
} else if (mask == (1 << 5) - 1) {
return -1;
} else {
return 0;
}
}
Variant 2a
int test(int a[5]) {
unsigned int mask = 0;
for (int i = 0; i < 5; i++) {
mask <<= 1;
mask |= a[i] >> numeric_limits<int>::digits;
}
if (mask == 0) {
return 1;
} else if (mask == (1 << 5) - 1) {
return -1;
} else {
return 0;
}
}
What Version should I prefer? Is there any adavantage using variant 2/2a over 1? Or is there a better/faster/cleaner way?
I think your question and what you're looking for don't agree. You asked how to detect if they're signed or unsigned, but it looks like you mean how to test if they're positive or negative.
A quick test for all negative:
if ((a[0]&a[1]&a[2]&a[3]&a[4])<0)
and all non-negative (>=0):
if ((a[0]|a[1]|a[2]|a[3]|a[4])>=0)
I can't think of a good way to test that they're all strictly positive (not zero) right off, but there should be one.
Note that these tests are correct and portable for twos complement systems (anything in the real world you would care about), but they're slightly wrong for ones complement or sign-magnitude. They might can be fixed if you really care.
I guess you mean negative/positive, (un)signed means whether a sign exists at all. This one works for any iterable (this assumes you count 0 as positive):
template <class T>
bool allpos(const T start, const T end) {
T it;
for (it = start; it != end; it++) {
if (*it < 0) return false;
}
return true;
}
// usage
int a[5] = {-5, 3, 1, 0, 4};
bool ispos = allpos(a, a + 5);
Note: This is a good and fast way
This may not be the absolutely extremely superduperfastest way to do it, but it certainly is readable and really fast. Optimizing this is just not worth it.
Variant 1 is the only readable one.
However, you could make it nicer using a loop:
int test(int *a, int n) {
int neg = 0;
for(int i = 0; i < n; i++) {
if(a[i] < 0) neg++;
}
if(neg == 0) return 1;
else if(neg == n) return -1;
else return 0;
}
I agree with previous posters that loops are simpler. The following solution combines Nightcracker's template and ThiefMaster's full solution, with early-outing if a sign-change is detected while looping over the variables (early-outing). And it works for floating point values.
template<typename T>
int testConsistentSigns(const T* i_begin, const T* i_end)
{
bool is_positive = !(*i_begin < 0);
for(const T* it = i_begin + 1; it < i_end; ++it)
{
if((*it < 0) && is_positive)
return 0;
}
if(is_positive)
return 1;
return -1;
}
In terms of speed, I suggest you profile each of your example in turn to discover which is the fastest on your particular platform.
In terms of ease of understanding, I'd say that the first example is the most obvious, though that's just my opinion.
Of course, the first version is a maintenance nightmare if you have more than 5 variables. The second and third variants are better for this, but obviously have a limit of 32 variables. To make them fully flexible, I would suggest keeping counters of the number of positive and negative variables, in a loop. After the end of the loop, just check that one or other counter is zero.
First off, create a method\procedure. That'll boost readability by a whole lot (no matter how you implement it, it'll be cleaner then all the options above).
Second, I think that the function:
bool isNeg(int x) { return x < 0;}
s cleaner then using bit masks, so I'll go with option 1, and when it comes to speed, let the compiler work that out for you in such low-level cases.
The final code should look something like:
int test(int a[5]) {
bool allNeg = true;
bool allPos = true;
for (i = 0; i < 5; i++){
if (isNeg(a[i]) allPos = false;
if (isPos(a[i]) allNeg = false;
}
if (allNeg) return -1;
if (allPos) return 1;
return 0;
}
You could find maximum element, if it is negative then all elements are negative:
template<typename T>
bool all_negative( const T* first, const T* last )
{
const T* max_el = std::max_element( first, last );
if ( *max_el < T(0) ) return true;
else return false;
}
You could use boost::minmax_element to find if all elements are negative/positive in one loop:
template<typename T>
int positive_negative( const T* first, const T* last )
{
std::pair<const T*,const T*> min_max_el = boost::minmax_element( first, last );
if ( *min_max_el.second < T(0) ) return -1;
else if ( *min_max_el.first > T(0) ) return 1;
else return 0;
}
If the sequence is non-empty, the function minmax_element performs at most 3 * (last - first - 1) / 2 comparisons.
If you only need to know less/greater than zero one at a time, or can be content with < and >= you can do it easily with find_if like this:
#include <iostream>
template <class Iter>
int all_neg(Iter begin, Iter end)
{
return std::find_if(begin, end, std::bind2nd(std::greater_equal<int>(), 0)) == end;
}
int main()
{
int a1[5] = { 1, 2, 3, 4, 5 };
int a2[5] = { -1, 2, 3, 4, 5 };
int a3[5] = { -1, -2, -3, -4, -5 };
int a4[5] = { 0 };
std::cout << all_neg(a1, a1 + 5) << ":"
<< all_neg(a2, a2 + 5) << ":"
<< all_neg(a3, a3 + 5) << ":"
<< all_neg(a4, a4 + 5) << std::endl;
}
You can also use a more complicated predicate that keeps track of any pos/neg to answer your original question if you really need that level of detail.