Unexplained discrepancies when copying and modifying std::strings - c++

In the following code, "situation 1" works as expected on all
compilers tested, however "situation 2" it seems to behave differently
based on the compiler used.
As an example MSVC has sit1 and sit2 produce the same results, however
when using gcc/clang and libstdc++, the modification occurs to the
original string and it's copy (sort of like a COW string) even though
I'm building using the C++11 switch.
#include <iostream>
#include <string>
int main() {
// situation 1
{
std::string x0 = "12345678";
std::string x1 = x0;
char* ptr = &x0[0] + 3;
(*ptr) = ' ';
std::cout << "1. x0: " << x0 << "\n";
std::cout << "1. x1: " << x1 << "\n";
if ((&x0[0]) == x0.data()) std::cout << "1. ptrs are equal\n";
}
// situation 2
{
std::string x0 = "12345678";
std::string x1 = x0;
char* ptr = const_cast<char*>(x0.data() + 3);
(*ptr) = ' ';
std::cout << "2. x0: " << x0 << "\n";
std::cout << "2. x1: " << x1 << "\n";
if ((&x0[0]) == x0.data()) std::cout << "2. ptrs are equal\n";
}
return 0;
}
GCC (6.1)
1. x0: 123 5678
1. x1: 12345678
1. ptrs are equal
2. x0: 123 5678
2. x1: 123 5678
2. ptrs are equal
MSVC (2015)
1. x0: 123 5678
1. x1: 12345678
1. ptrs are equal
2. x0: 123 5678
2. x1: 12345678
2. ptrs are equal
Is there any reason for the discrepancies in behavior between the various compilers - given that &x0[0] and .data() return the same address?

Situation 2 causes undefined behaviour:
char* ptr = const_cast<char*>(x0.data() + 3);
(*ptr) = 'Z';
According to the specification of std::basic_string::data (C++14 [string.accessors]/3):
Requires: The program shall not alter any of the values stored in the character array.
In other words, you are not allowed to cast away the const and modify the string via the pointers returned by data() or c_str() .

Related

How to get Real value precision in C++ Same as Fortran (Pararel Studio XE Compiler)

I have an almost large Fortran 77 code which I'm trying to write it in c++.
the Fortran code has too many math formulas and i have to get same parameter value in c++.
I have a code like this in Fortran :
implicit real*8 (a-h,o-z)
real *8 test
test=3.14159**2
print *,test
And output is : 9.86958772810000
In the c++ code (i use pow for just a sample i have this problem in every math formula):
// 1st Try
double test=pow(3.14159,2);
cout <<std::setprecision(std::numeric_limits<double>::digits10 + 1) <<fixed <<test;
And output is : 9.86958885192871
I know that i can specify the kind of a f-p number by suffixing the kind-selector like this (but it's for fortran i need to get same value in c++
0:
real test=3.14159_8**2
As is described in this question Different precision in C++ and Fortran
i also tried this in c++ and the output was :
// 2nd Try as users suggested in the comments
float test2 = pow(3.14159, 2);
the output 9.8695878982543945
and if i try :
// 3rd Try as users suggested in the comments
float test2 = pow(3.14159f, 2);
output will be : 9.8695888519287109
which still has differences.
** I need to get same value in c++ not Fortran** because the Fortran project uses this parameter all over the project and i have to get same output.
So is there anyway i get same Float/Double precision in c++?
For Fortran i use Pararel Studio XE Compiler 2017
For c++ Visual Studio 2017
Any help would be appreciated.(thank you all for helping).
as Kerndog73 Asked i tried
std::numeric_limits<double>::digits // value is 53
std::numeric_limits<double>::is_iec559 //value is 1
P.S: More Detail
It's one part of my original FORTRAN code, as you can see i need to have all 10 precision in c++ to get same values (this code draws a shape in a text file at the end of the code, and my c++ code is not similar to that shape because precision values are not the same):
// in the last loop i have a value like this 9292780397998.33
// all precision have used
dp=p2-p1
dr=(r2-r1)/(real(gx-1))
dfi=2*3.14159*zr/(real(gy-1))
test=3.14159**2
print *,test
r11=r1
print *,'dp , dr , dfi'
print *,dp,dr,dfi
do 11 i=1,gx
r(i)=r11
st(i)=dr*r(i)*dfi
r11=r11+dr
print *, r11,r(i),st(i)
11 continue
dh=h02-h01
do 1 i=1,gx
do 2 j=1,gy
h0=h01+dh*(r(i)-r1)/(r2-r1)
hkk=hk(i,j)
if (hkk.eq.10) then
hk(i,j)=hkkk
end if
h00=h0+hk(i,j)
h(i,j)=h00/1000000.
!print *, i,j, h(i,j)
!print*, h(i,j)
2 continue
1 continue
!
! write(30,501) ' '
do 12 i=1,gx
do 22 j=1,gy
h3=h(i,j)**3
h3r(i,j)=h3*r(i)
h3ur(i,j)=h3/r(i)
!print *,i,j, h3ur(i,j)
p0(i,j)=p1+dp*(r(i)-r1)/(r2-r1)
!print *,i,j, p0(i,j)
22 continue
12 continue
drfi=dr/(dfi*48*zmu)
dfir=dfi/(dr*48*zmu)
omr=om*dr/8.
print *,'drfi,dfir,omr,zmu'
print *,drfi,dfir,omr,zmu
!p1 = 10000
!do 100 k=1,giter
do 32 i=1,gx
do 42 j=1,gy
if (i.eq.1) then
pp(i,j)=p1**2
goto 242
end if
if (i.eq.gx) then
pp(i,j)=p2**2
goto 242
end if
if (j.eq.1.) then
temp1=drfi*(2*h3ur(i,1)+h3ur(i,(gy-1))+h3ur(i,2))
a=drfi*(2*h3ur(i,1)+h3ur(i,(gy-1))+h3ur(i,2))+
& dfir*(2*h3r(i,1)+h3r(i-1,1)+h3r(i+1,1))
& -omr*r(i)*(h(i,(gy-1))-h(i,2))/p0(i,1)
b=drfi*(h3ur(i,1)+h3ur(i,(gy-1)))+
& omr*r(i)*(h(i,(gy-1))+h(i,1))/p0(i,(gy-1))
c=drfi*(h3ur(i,1)+h3ur(i,2))-
& omr*r(i)*(h(i,1)+h(i,2))/p0(i,2)
d=dfir*(h3r(i,1)+h3r(i-1,1))
e=dfir*(h3r(i,1)+h3r(i+1,1))
pp(i,j)=(b*p0(i,(gy-1))**2+c*p0(i,2)**2+
& d*p0(i-1,1)**2+e*p0(i+1,1)**2)/a
goto 242
end if
if (j.eq.gy) then
a=drfi*(2*h3ur(i,gy)+h3ur(i,(gy-1))+h3ur(i,2))+
& dfir*(2*h3r(i,gy)+h3r(i-1,gy)+h3r(i+1,gy))
& -omr*r(i)*(h(i,(gy-1))-h(i,2))/p0(i,gy)
b=drfi*(h3ur(i,gy)+h3ur(i,(gy-1)))+
& omr*r(i)*(h(i,(gy-1))+h(i,gy))/p0(i,(gy-1))
c=drfi*(h3ur(i,gy)+h3ur(i,2))-
& omr*r(i)*(h(i,gy)+h(i,2))/p0(i,2)
d=dfir*(h3r(i,gy)+h3r(i-1,gy))
e=dfir*(h3r(i,gy)+h3r(i+1,gy))
pp(i,j)=(b*p0(i,(gy-1))**2+c*p0(i,2)**2+
& d*p0(i-1,gy)**2+e*p0(i+1,gy)**2)/a
goto 242
end if
a=drfi*(2*h3ur(i,j)+h3ur(i,j-1)+h3ur(i,j+1))+
& dfir*(2*h3r(i,j)+h3r(i-1,j)+h3r(i+1,j))
& -omr*r(i)*(h(i,j-1)-h(i,j+1))/p0(i,j)
b=drfi*(h3ur(i,j)+h3ur(i,j-1))+
& omr*r(i)*(h(i,j-1)+h(i,j))/p0(i,j-1)
c=drfi*(h3ur(i,j)+h3ur(i,j+1))-
& omr*r(i)*(h(i,j)+h(i,j+1))/p0(i,j+1)
d=dfir*(h3r(i,j)+h3r(i-1,j))
e=dfir*(h3r(i,j)+h3r(i+1,j))
pp(i,j)=(b*p0(i,j-1)**2+c*p0(i,j+1)**2+
& d*p0(i-1,j)**2+e*p0(i+1,j)**2)/a
242 continue
ppp=pp(i,j)
print *,ppp
pneu=sqrt(ppp)
palt=p0(i,j)
p0(i,j)=palt+(pneu-palt)/2.
!print *,p0(i,j)
wt(i,j)=zmu*om*om*((r(i)+dr)**2+r(i)**2)/(2*h(i,j))
!print *,r(i)
p00(i,j)=p0(i,j)/100000.
!print *, p00(i,j)
42 continue
32 continue
I wrote a program to output all possible results in the 3 formats, with casting done to each type at the various possible times:
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
// use `volatile` extensively to inhibit "float store" optimizations
template<class T>
void pp(volatile T val)
{
const size_t prec = std::numeric_limits<T>::digits10 + 1;
std::cout << std::setprecision(prec);
std::cout << std::left;
std::cout << std::setfill('0');
std::cout << std::setw(prec+2) << val;
}
int main()
{
using L = long double;
using D = double;
using F = float;
volatile L lp = 3.14159l;
volatile D dp = 3.14159;
volatile F fp = 3.14159f;
volatile L lpl = lp;
volatile D dpl = lp;
volatile F fpl = lp;
volatile L lpd = dp;
volatile D dpd = dp;
volatile F fpd = dp;
volatile L lpf = fp;
volatile D dpf = fp;
volatile F fpf = fp;
volatile L lpl2 = powl(lpl, 2);
volatile D dpl2 = pow(dpl, 2);
volatile F fpl2 = powf(fpl, 2);
volatile L lpd2 = powl(lpd, 2);
volatile D dpd2 = pow(dpd, 2);
volatile F fpd2 = powf(fpd, 2);
volatile L lpf2 = powl(lpf, 2);
volatile D dpf2 = pow(dpf, 2);
volatile F fpf2 = powf(fpf, 2);
std::cout << "lpl2: "; pp((L)lpl2); std::cout << " "; pp((D)lpl2); std::cout << " "; pp((F)lpl2); std::cout << '\n';
std::cout << "dpl2: "; pp((L)dpl2); std::cout << " "; pp((D)dpl2); std::cout << " "; pp((F)dpl2); std::cout << '\n';
std::cout << "fpl2: "; pp((L)fpl2); std::cout << " "; pp((D)fpl2); std::cout << " "; pp((F)fpl2); std::cout << '\n';
std::cout << "lpd2: "; pp((L)lpd2); std::cout << " "; pp((D)lpd2); std::cout << " "; pp((F)lpd2); std::cout << '\n';
std::cout << "dpd2: "; pp((L)dpd2); std::cout << " "; pp((D)dpd2); std::cout << " "; pp((F)dpd2); std::cout << '\n';
std::cout << "fpd2: "; pp((L)fpd2); std::cout << " "; pp((D)fpd2); std::cout << " "; pp((F)fpd2); std::cout << '\n';
std::cout << "lpf2: "; pp((L)lpf2); std::cout << " "; pp((D)lpf2); std::cout << " "; pp((F)lpf2); std::cout << '\n';
std::cout << "dpf2: "; pp((L)dpf2); std::cout << " "; pp((D)dpf2); std::cout << " "; pp((F)dpf2); std::cout << '\n';
std::cout << "fpf2: "; pp((L)fpf2); std::cout << " "; pp((D)fpf2); std::cout << " "; pp((F)fpf2); std::cout << '\n';
return 0;
}
On my Linux system, this outputs:
long double double float
lpl2: 9.869587728100000000 9.869587728100001 9.869588
dpl2: 9.869587728099999069 9.869587728099999 9.869588
fpl2: 9.869588851928710938 9.869588851928711 9.869589
lpd2: 9.869587728099999262 9.869587728099999 9.869588
dpd2: 9.869587728099999069 9.869587728099999 9.869588
fpd2: 9.869588851928710938 9.869588851928711 9.869589
lpf2: 9.869588472080067731 9.869588472080068 9.869589
dpf2: 9.869588472080067731 9.869588472080068 9.869589
fpf2: 9.869588851928710938 9.869588851928711 9.869589
Base on this, it's possible that you're showing too few digits but Intel's 80-bit format, which is long double on Linux (and, I believe, most x86 OSes), but normally unavailable on Windows.
It's also possible that you're using decimal floats.
But it's also possible your Fortran runtime was just plain broken, many float<->string libraries can generously be described as COMPLETE AND UTTER CRAP.
It's a good habit to use hexadecimal float I/O for reliability.
Use a multiprecision arithmetic library for C++ that gives you more control over the format of numeric values than float, double, etc. in C++.
For example, using Boost.Multiprecision the following code
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iomanip>
int main() {
using number = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<8>>;
number pi_five_sig_digits{ 3.14159 };
number value = boost::multiprecision::pow(pi_five_sig_digits, number(2));
std::cout << "3.14159 ** 2 = " << std::setprecision(15) << value << std::endl;
return 0;
}
yields
3.14159 ** 2 = 9.8695877281
The way that can work in cout until now is what #kerndog73 suggested.(thank you so much)
but my poblem would not solve with cout
#include <cmath>
#include <iomanip>
#include <iostream>
constexpr int prec = std::numeric_limits<double>::digits10 - 1;
int main() {
const double testD = std::pow(3.14159, 2.0);
const float testF = std::pow(3.14159f, 2.0f);
std::cout << "Double: " << std::setprecision(prec) << std::fixed << testD << '\n';
std::cout << "Float: " << std::setprecision(prec) << std::fixed << testF << '\n';
}
and outputs are :
Double
9.86958772810000 // exactly same as FORTRAN 77 output
Float
9.86958885192871

Why does this stringstream fail when parsing into double?

I have the following code:
#include <string>
#include <iostream>
#include <sstream>
int main()
{
size_t x, y;
double a = std::stod("1_", &x);
double b = std::stod("1i", &y);
std::cout << "a: " << a << ", x: " << x << std::endl;
std::cout << "b: " << b << ", y: " << y << std::endl;
std::stringstream s1("1_");
std::stringstream s2("1i");
s1 >> a;
s2 >> b;
std::cout << "a: " << a << ", fail: " << s1.fail() << std::endl;
std::cout << "b: " << b << ", fail: " << s2.fail() << std::endl;
}
I want to parse a double and stop when an invalid character is hit. Here I try to parse "1_" and "1i", both of which should give me the double with value: 1.
here is my output:
a: 1, x: 1
b: 1, y: 1
a: 1, fail: 0
b: 0, fail: 1
So the stod function worked as expected, however the stringstream method did not. It makes no sense to me that 2 standard methods of parsing double, both in the standard library would give different results?
Why does the stringstream method fail when parsing: "1i"?
Edit:
this appears to give different results for some people. My compiler info is the following:
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Edit2:
Is this a bug with libc++, or is the specification just vague about what counts as valid parsing for a double?
This is a libc++ bug. Per [facet.num.get.virtuals] bullet 3.2, a character is only supposed to be accumulated if it is allowed as the next character of the input field of the conversion specifier determined in stage 1 (%g for double). Having accumulated 1, i is not allowed, so stage 2 should terminate.
libc++ is accumulating characters indiscriminately until it reaches a non-atom character (it also extended the atoms to include i, which is required to parse inf).

using std::sort and std::next_permutation

I have the following code which i wrote and works perfectly. I just have trouble understanding why it works. More specifically, why must we first sort the array in order to use std::next_permutation, can it not start from any configuration ?
And the part which bothers me the most is that I don't understand why we must write
sort(sides, sides+3) and next_permutation(sides, sides+3) why the "+3"! because I have three elements in the array ? What if i was using an arbitrary number of elements ?
bool valid(int sides[], ofstream &outfile)
{
int i = 0;
for(; i < 3; i++) {
if(sides[i] <= 0) {
outfile << "This is not a valid triangle because it\n "
<< "contains negative sides or contains a\n"
<< "side length of 0\n\n";
return false;
}
}
do{
std::sort(sides,sides+3);
if(sides[0] + sides[1] > sides[2])
;
else{
outfile << "This is not a valid triangle because "
<< sides[0] << " + " << sides[1]
<< " is not greater than " << sides[2];
return false;
}
}while(std::next_permutation(sides,sides+3));
return true;
}
Euclidian geometry tells us that:
the sum of two sides is always greater than the remaining side
Lets take a triangle ABC.
AB = 3
BC = 5
AC = 4
std::sort will sort the sides into ascending order. So that the array will contain the shorter sides first.
after sort
side[0] = AB = 3
side[1] = AC = 4
side[2] = BC = 5
std::next_permutation returns the next possible combination of the sides.For instance:
AC = 3
BC = 5
AB = 4
A quick example:
#include <iostream> // std::cout
#include <algorithm> // std::next_permutation, std::sort
int main () {
int myints[] = {1,2,3};
std::sort (myints,myints+3);
std::cout << "The 3! possible permutations with 3 elements:\n";
while ( std::next_permutation(myints,myints+3) )
{
std::cout << myints[0] << ' ' << myints[1];
std::cout << ' ' << myints[2] << '\n';
}
std::cout << "After loop: " << myints[0] << ' ';
std::cout << myints[1] << ' ' << myints[2] << '\n';
return 0;
}
Further reading: http://www.cplusplus.com/reference/algorithm/next_permutation/
the std::next_permutation documentation
Transform range to next permutation Rearranges the elements in the
range [first,last) into the next lexicographically greater
permutation.
so unless you start sorted you won't go through all permutations
So if you start with
1,2,3
that last permutation would be
3,2,1
if you start from
3,1,2
only one more permutation will be found and not all
Take a look at the results of std::next_permuntation when you don't sort it:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
enum class sort { no, yes };
void show_permutations(std::string s, sort option) {
if (sort::yes == option) {
std::sort(std::begin(s), std::end(s));
}
do {
std::cout << s << '\n';
} while (std::next_permutation(std::begin(s), std::end(s)));
}
int main() {
show_permutations("3412", sort::yes);
std::cout << "Now without sorting...\n";
show_permutations("3412", sort::no);
}
Examine the output to see if you notice anything interesting:
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321
Now without sorting...
3412
3421
4123
4132
4213
4231
4312
4321
The sequence created without sorting is the same as just the very end of the sequence created with sorting. What does that imply about the importance of the input's ordering?
What do you think would happen if you put the sorting code inside the loop?
void show_permutations(std::string s, sort option) {
do {
if (sort::yes == option) {
std::sort(std::begin(s), std::end(s));
}
std::cout << s << '\n';
} while (std::next_permutation(std::begin(s), std::end(s)));
}
Notice that your program sorts the triangle sides inside the next_permutation loop similar to this code sorting the input string inside the loop.

ostream: prefix a positive number with a space

In C a space can be included in a printf formatting flag which results in positive numbers being prefixed with a space. This is a useful feature for aligning signed values. I can't figure out how to do the same in C++. In C:
double d = 1.2;
printf("%f\n",d);
printf("%+f\n",d);
printf("% f\n",d);
produces:
1.2
+1.2
1.2
Using ostream, I can do the first two, but how do I do the third?
int d = 1.2;
std::cout << d << std::endl;
std::cout << std::showpos << d << std::endl;
// ??????????????
EDIT: There seems to be some confusion about whether or not I just want to prefix all of my values with a space. I only want to prefix positive values with a space, similar to a) like the printf space flag does and b) similar to what showpos does, except a space rather than a '+'. For example:
printf("%f\n", 1.2);
printf("%f\n", -1.2);
printf("% f\n", 1.2);
printf("% f\n", -1.2);
1.2
-1.2
1.2
-1.2
Note that the third value is prefixed with a space while the fourth (negative) value is not.
You can use setfill and setw, like this:
cout << setw(4) << setfill(' ') << 1.2 << endl;
cout << setw(4) << setfill(' ') << -1.2 << endl;
This produces the following output:
1.2
-1.2
Don't forget to include <iomanip> in order for this to compile (link to ideone).
I don't have my standard with me and I'm doing this stuff too rarely to be confident about it: There are two ingredients to achieving this with IOStreams:
Use std:: showpos to have an indicator of positive values be shown. By default this will use +, of course.
I think the + is obtained using std::use_facet<std::ctype<char> >(s.get_loc()).widen('+'). To turn this into a space you could just use a std::locale with a std::ctype<char> facet installed responding with a space to the request to widen +.
That is, something like this:
struct my_ctype: std::ctype<char> {
char do_widen(char c) const {
return c == '+'? ' ': this->std::ctype<char>::do_widen(c);
}
};
int main() {
std::locale loc(std::locale(), new my_ctype);
std::cout.imbue(loc);
std::cout << std::showpos << 12.34 << '\n';
}
(the code isn't tested and probably riddled with errors).
How about
std::cout << (d >= 0 ? " ":"") << d << std::endl;
std::cout << " " << my_value;
If you need space only for positive:
if (my_value >=0 ) cout << " "; cout << my_value;

Why setting null in the middle of std string doesn't have any effect

Consider
#include <string>
#include <iostream>
int main()
{
/*
hello
5
hel
3
*/
char a[] = "hello";
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
a[3] = 0;
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
/*
hello
5
hel o
5
*/
std::string b = "hello";
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
b[3] = 0;
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
getchar();
}
I expect std::string will behave identical to char array a. That's it, insert null character in the middle of the string, will "terminate" the string. However, it is not the case. Is my expectation wrong?
A std::string is not like a usual C string, and can contain embedded NUL characters without problems. However, if you do this you will notice the string is prematurely terminated if you use the .c_str() function to return a const char *.
No - std::strings are not NUL-terminated like C "strings"; the std::string records its length independently.
#Lou is right: don't do that. Instead, do this:
b.erase (3, b.length());
Yes, your expectation is wrong. std::string is meant to be different from C strings (e.g. not necessarily stored in consecutive memory / an array).
To duplicate the first section's behavior, try std::cout << b.c_str() instead of std::cout << b.
I expect std::string will behave identical to char array a.
Why? Nothing in the documentation, anywhere, having to do with std::string says it does this.
My suggestion, stop treating like C++ as C plus some stuff.