Let's imagine the following table ...
obs
State
Imp
i
i2
1
me
100
100
2
me
90
100
100
3
me
80
100
100
4
me
70
100
100
5
me
1000
1000
100
6
me
900
1000
1000
7
me
800
1000
1000
8
me
0
1000
1000
9
me
2000
2000
1000
10
me
1900
2000
2000
11
gu
20
2000
2000
12
ca
40
2000
2000
13
ca
50
2000
2000
14
ca
30
2000
2000
15
ca
10
2000
2000
as you can see column "i2" is lag (i). What I want to do is:
1.- column "i" finds the maximum value as it progresses, so i want to reset that column
"i" every first "state", in order to get that maximum value of each state.
2.- modify the column "i2" so that it is as follows:
that each first value of "State" (obs 1-me, 11-gu and 12-ca) column "i" has the value
of column "imp"
obs
State
Imp
i
i2
1
me
100
100
100
2
me
90
100
100
3
me
80
100
100
4
me
70
100
100
5
me
1000
1000
100
6
me
900
1000
1000
7
me
800
1000
1000
8
me
0
1000
1000
9
me
2000
2000
1000
10
me
1900
2000
2000
11
gu
20
20
20
12
ca
40
40
40
13
ca
50
50
40
14
ca
30
50
50
15
ca
10
50
50
i have tried with this code, but it doesn't work
data metodo;
set sa80;
retain i;
if first.state then i=max(imp);
else i = max(imp,i);
i2 = lag(i);
run;
data final;
set metodo;
retain i2_aux;
if first.state then i2_aux = total;
else i2_aux = i2;
run;
Hope you could help, and thank you in advance
The main thing it not use an existing variable as the new RETAINed variable because then each time the SET statement executes the value retained is replaced with the value read from the input.
It also helps if the data is sorted by the key variable, although you can use the NOTSORTED keyword on the BY statement to process grouped, but not sorted, data.
data have;
input state $ imp ;
cards;
ca 40
ca 50
ca 30
ca 10
gu 20
me 100
me 90
me 80
me 70
me 1000
me 900
me 800
me 0
me 2000
me 1900
;
data want;
set have ;
by state notsorted;
retain i;
i=max(i,imp);
if first.state then i=imp;
i2=lag(i);
if first.state then i2=imp;
run;
Results:
Obs state imp i i2
1 ca 40 40 40
2 ca 50 50 40
3 ca 30 50 50
4 ca 10 50 50
5 gu 20 20 20
6 me 100 100 100
7 me 90 100 100
8 me 80 100 100
9 me 70 100 100
10 me 1000 1000 100
11 me 900 1000 1000
12 me 800 1000 1000
13 me 0 1000 1000
14 me 2000 2000 1000
15 me 1900 2000 2000
Fixed order of resetting I and LAG(I) call.
SAS EG gives these errors:
ERROR: Expression using not equals (^=) has components that are of
different data types.
ERROR: Expression using equals (=) has components that are of
different data types.
for this line:
on I.app_id = v.appl_id
proc contents on both fields are Type= Char, Len = 15, Format =$15.00, Informat=$15.00.
I inherited this project and I'm very new to SAS. Any help greatly appreciated.
The CONTENTS Procedure
Data Set Name TEMP7D.DFS_VER_PANEL Observations 8953153
Alphabetic List of Variables and Attributes
# Variable Type Len Format Informat
1 APPL_ID Char 15 $15.00 $15.00
2 VER_MAKE_NAME Char 36 $36.00 $36.00
3 VER_MODEL_NAME Char 50 $50.00 $50.00
6 cash_down Num 8 13.2 13.2
4 cash_price Num 8 13.2 13.2
15 collat_val Num 8 13.2 13.2
12 dealer_adds Num 8 13.2 13.2
16 gap_fee Num 8
18 gapi_fee Num 8
17 gapw_fee Num 8
9 net_trade_in Num 8 13.2 13.2
8 owing_on_trade Num 8 13.2 13.2
5 rebate Num 8 13.2 13.2
13 sales_tax_fees Num 8 13.2 13.2
19 tot_be_wgap Num 8
10 tot_down_pmt Num 8 13.2 13.2
14 total_amt_financed Num 8 13.2 13.2
7 trade_in Num 8 13.2 13.2
11 unpaid_cash_bal Num 8 13.2 13.2
The CONTENTS Procedure
Data Set Name TEMP7D.INFILE_1 Observations 1852630
Alphabetic List of Variables and Attributes
# Variable Type Len Format Informat
63 AMT_APP_VER_FINANCED Num 8 13.2 13.2
62 AMT_APRV Num 8 13.2 13.2
61 AMT_APRV_FINCD Num 8 13.2 13.2
65 AMT_APRV_PMT Num 8 11.2 11.2
73 AMT_COLLAT Num 8 13.2 13.2
41 AMT_DLR_RESV Num 8
66 AMT_INC_TOT Num 8 15.2 15.2
15 AMT_ORIG_NOTE Num 8
64 AMT_RQSTD Num 8 13.2 13.2
11 AMT_TOT_ANN_INC Num 8
37 AMT_VER_RATE Num 8 9.3 9.3
2 APP_ID Char 15 $15.00 $15.00
14 CDE_ACCT_STAT Char 2 $2.00 $2.00
74 CDE_ACL_NEW_USED Char 1 $1.00 $1.00
75 CDE_ACL_YEAR Num 8 3 3
43 CDE_ADJ_USER_CUR Char 8 $8.00 $8.00
29 CDE_CREDIT_ANALYST Char 6 $6.00 $6.00
54 CDE_DIST_PLAN Num 8
44 CDE_LOCATION Char 6 $6.00 $6.00
69 CDE_NEW_USED_COLL Char 3 $3.00 $3.00
27 CDE_OFFICER_APRV Char 6 $6.00 $6.00
28 CDE_OFFICER_CUR Char 6 $6.00 $6.00
55 CDE_PAYOFF_CHARGEBACK Char 3 $3.00 $3.00
25 CDE_PROD_APRV Char 5 $5.00 $5.00
26 CDE_PROD_RQSTD Char 5 $5.00 $5.00
70 COLL_MAKE Char 100 $100.00 $100.00
71 COLL_MODEL Char 100 $100.00 $100.00
72 COLL_YR Char 4 $4.00 $4.00
110 CRS Num 8
56 CURR_UW Char 30 $30.00 $30.00
9 CUSTOM_SCORE Num 8
87 CompareVar Num 8
45 DEALER_CODE Char 5 $5.00 $5.00
48 DEALER_NAME Char 30 $30.00 $30.00
52 DLRACTIVE Char 1 $1.00 $1.00
51 DLRMSA Char 5 $5.00 $5.00
49 DLRSTATE Char 2 $2.00 $2.00
50 DLRZIP Char 9 $9.00 $9.00
13 DLR_NUM_KEY_1 Char 30 $30.00 $30.00
60 DRAG_REDUCTION Num 8
40 DTE_ENTERED Num 8 DATETIME20. DATETIME20.
5 DTE_ORIG_PROCESS Num 8 DATETIME20. DATETIME20.
1 DW_ACCT_KEY Num 8
93 DlrZipClean Char 5
81 FCTR Num 8
20 FTP_RATE Num 8
102 FicoBand Num 8
19 GLAdjBal Num 8
39 ID_PROMOTIONAL Char 18 $18.00 $18.00
42 IND_DLR_FLAT_FEE Char 1 $1.00 $1.00
21 IND_SOLD Char 1 $1.00 $1.00
12 LTV Num 8
53 MARKET_REP_NAME Char 50 $50.00 $50.00
34 MAXCUSTSCOR Num 8
58 NME_DLR_GROUP Char 50 $50.00 $50.00
32 NUM_ACL_MILEAGE Num 8 7 7
10 NUM_ORIG_TERM Num 8
22 NUM_POOL Char 4 $4.00 $4.00
24 NUM_TERM Num 8 6 6
6 ORIGDATEEOM Num 8 DATETIME20. DATETIME20.
7 ORIG_CR_SCORE Num 8
88 OrigDate Num 8 DATE9.
33 PAYMENT Num 8
59 PAYOFF_PERIOD Num 8
35 PCT_APP_RECOMMEND_RATE Num 8 9.3 9.3
16 PCT_APR_RTE Num 8 13.7 13.7
36 PCT_BANK_BUY_RATE Num 8 9.3 9.3
30 PCT_BUY_DOWN_RATE Num 8 8.3 8.3
31 PCT_DLR_FLAT_FEE_RATE Num 8 8.3 8.3
18 PCT_DLR_RATE Num 8
8 PCT_ORIG_DTI Num 8
17 PCT_RATE Num 8
23 PMT_TO_INCOME Num 8 16.3 16.3
4 PROD_KEY_2 Char 20 $20.00 $20.00
46 REC_RATE Num 8
38 RO_OVERRIDE_CODE Char 2 $2.00 $2.00
3 SRC_SYS_ACCT_KEY Char 20 $20.00 $20.00
68 TFLFlg Num 8
57 TXT_CENTER Char 15 $15.00 $15.00
103 TermBand Num 8
76 VEHICLE_TYPE Char 120 $120.00 $120.00
47 VER_RATE Num 8 9.3 9.3
94 VehYr4 Char 7
89 Vintage Num 8
90 VintageHalf Char 6 $6.00
92 VintageMon Char 7 $7.00
91 VintageQtr Char 6 $6.00
95 amt Num 8 10.2
107 aprround Num 8 10.3
101 back_end_exc Num 8
106 bkround Num 8 10.3
99 cs_exceptions Num 8
85 cust_scr Num 8
105 dlrsplit Num 8 10.3
79 docst_fee Num 8
83 estdrl1 Num 8
67 exception Num 8
80 fchg_fee Num 8
100 hd Char 3
108 ltv_PreBE Num 8 10.2
96 new_used Num 8
104 oac Char 1
86 orig_cr_scoreAdj Num 8
82 pct_bk_rate Num 8
98 price_except Num 8
109 pti_PreBE Num 8 10.2
97 region Num 8
77 segment Char 29
84 term Num 8
78 total_backend_fees Num 8
/* CREATE TABLE TEMP7D.InFile_2 AS*/
SELECT DISTINCT
I.*,
D.pp AS PP_bkround,
D2.pp AS PP_aprround,
PEL.new AS PelNew,
PEL.used AS PelUsed,
ELA.Add_ON AS ElaAddOnHist,
ELA_LTV.Factor AS ELAFactor_LTV,
ELA_OAC.Factor AS ELAFactor_OAC,
ELA_Term.Factor AS ELAFactor_Term,
ELAF.NEW AS ElafNew,
ELAF.USED AS ElafUsed,
ELAL.ADD_ON AS ElalAddOn,
PCS.Points AS CSPoints,
PFICO.Points AS FicoPoints,
PLTV.Points AS LTVPoints,
PPMT.Points AS PMTPoints,
PPTI.Points AS PTIPoints,
COALESCE(FIP.FIP,FIP2.FIP) AS FIP,
COALESCE(FIP.MSA,FIP2.MSA) AS MSA,
ADJ.ELGeoAdj,
CASE
WHEN F.src_sys_acct_key NE ''
THEN 1
ELSE 0
END AS FraudFlg,
CASE
WHEN S.src_sys_acct_key NE ''
THEN 1
ELSE 0
END AS SoldFlg,
CASE
WHEN S2.src_sys_acct_key NE ''
THEN 1
ELSE 0
END AS SecureFlg,
(-1*ND.value) AS Net_Drag_2,
v.ver_make_name,
PD1.Factor AS LTVFactor,
PD2.Factor AS PTIFactor,
PD3.Factor As TermFactor,
EAD.Factor AS EADFactor,
case
when year(datepart(dte_entered)) LT 2013
then coalesce(C.CreditSeg,4)
else coalesce(C.CreditSeg,999)
end AS CreditSeg,
case
when year(datepart(dte_entered)) LT 2013
then coalesce(C.CreditSource,2)
else C.CreditSource
end format CredSrcFmt. As CreditSource
FROM TEMP7D.InFile_1 AS I
/*
The Sandbox.DFSDrag table was updated in Dec. 2018 with new prepayment
rates. APR was no longer part of the criteria so I set this
variable = 9999 to indicate the new prepayment data. FICO and
TERM bands have changed as well. The previous prepayment data
is still stored in this table as well and can be identified
where APR <> 9999.
*/
LEFT JOIN Sandbox.DFSDrag AS D
ON I.New_used = d.New_used
AND I.orig_cr_score BETWEEN D.fico_start AND D.fico_end
AND I.num_term BETWEEN D.term_start AND D.term_end
AND D.apr = 9999
LEFT JOIN Sandbox.DFSDrag AS D2
ON I.New_used = d2.New_used
AND I.orig_cr_score BETWEEN D2.fico_start AND D2.fico_end
AND I.num_term BETWEEN D2.term_start AND D2.term_end
AND D2.apr = 9999
/*These two tables were updated based on changes to the EL model.
The original table was kept (Version = 0).
Factors effective November 2016 (Version 1)
Factors effective September 2017 (Version 2)*/
LEFT JOIN Sandbox.DFS_EL_PEL AS PEL
ON I.dte_entered BETWEEN PEL.el_sm AND PEL.el_em
AND COALESCE(I.orig_cr_score, 0) BETWEEN PEL.fsmin AND PEL.fsmax
AND COALESCE(I.custom_score, COALESCE(I.cust_scr, 0)) BETWEEN PEL.csmin AND PEL.csmax
AND PEL.Version = 2
LEFT JOIN Sandbox.DFS_EL_ELA2 AS ELA
ON I.dte_entered BETWEEN ELA.el_sm AND ELA.el_em
AND ELA.hd = I.hd
AND ELA.oac = I.oac
AND I.num_term BETWEEN ELA.term_min AND ELA.term_max
AND I.ltv BETWEEN ELA.ltv_min AND ELA.ltv_max
AND ELA.new_used = I.new_used
AND ELA.CRS = I.CRS
AND ELA.Version = 2
AND datepart(ELA.EL_EM) NE '31Dec9999'd
LEFT JOIN Sandbox.DFS_EL_ELA3 AS ELA_LTV
ON datepart(I.dte_entered) BETWEEN ELA_LTV.StartDate and ELA_LTV.EndDate
AND I.Cust_Scr BETWEEN ELA_LTV.CustScore_Min and ELA_LTV.CustScor_Max
AND I.num_term BETWEEN ELA_LTV.Term_Min AND ELA_LTV.Term_Max
AND I.LTV BETWEEN ELA_LTV.LTV_Min AND ELA_LTV.LTV_Max
AND I.New_Used = ELA_LTV.New_Used
AND ELA_LTV.Metric EQ 'LTV'
LEFT JOIN Sandbox.DFS_EL_ELA3 AS ELA_OAC
ON datepart(I.dte_entered) BETWEEN ELA_OAC.StartDate and ELA_OAC.EndDate
AND I.New_Used = ELA_OAC.New_Used
AND I.oac = ELA_OAC.oac
AND I.Cust_Scr BETWEEN ELA_OAC.CustScore_Min and ELA_OAC.CustScor_Max
AND I.num_term BETWEEN ELA_OAC.Term_Min AND ELA_OAC.Term_Max
AND I.LTV BETWEEN ELA_OAC.LTV_Min AND ELA_OAC.LTV_Max
AND ELA_OAC.Metric EQ 'OAC'
LEFT JOIN Sandbox.DFS_EL_ELA3 AS ELA_Term
ON datepart(I.dte_entered) BETWEEN ELA_Term.StartDate and ELA_Term.EndDate
AND I.New_Used = ELA_Term.New_Used
AND I.Cust_Scr BETWEEN ELA_Term.CustScore_Min and ELA_Term.CustScor_Max
AND I.num_term BETWEEN ELA_Term.Term_Min AND ELA_Term.Term_Max
AND I.LTV BETWEEN ELA_Term.LTV_Min AND ELA_Term.LTV_Max
AND ELA_Term.Metric EQ 'Term'
LEFT JOIN Sandbox.dfs_el_adj_factor As ELAF
ON I.num_term BETWEEN ELAF.term_min AND ELAF.term_max
AND I.ltv BETWEEN ELAF.ltv_min AND ELAF.ltv_max
LEFT JOIN Sandbox.dfs_el_ltv_adj_mar2016 As ELAL
ON ELAL.new_used = I.new_used
AND I.ltv BETWEEN ELAL.ltv_min AND ELAL.ltv_max
LEFT JOIN Sandbox.DFS_Points PCS
ON PCS.JoinVar = COALESCE(I.custom_score, COALESCE(I.cust_scr, 0))
AND PCS.PointType EQ 'CustomScorePoints'
LEFT JOIN Sandbox.DFS_Points PFICO
ON PFICO.JoinVar = COALESCE(I.orig_cr_score, 0)
AND PFICO.PointType EQ 'FicoPoints'
LEFT JOIN Sandbox.DFS_Points PLTV
ON PLTV.JoinVar = INT(I.ltv)
AND PLTV.PointType EQ 'LTVPoints'
LEFT JOIN Sandbox.DFS_Points PPMT
ON PPMT.JoinVar = FLOOR(I.payment)
AND PPMT.PointType = 'PMTPoints'
LEFT JOIN Sandbox.DFS_Points PPTI
ON INT(PPTI.JoinVar*10)/10 = INT(I.pmt_to_income*10)/10
AND PPTI.PointType = 'PTIPoints'
LEFT JOIN decan1.zipfip_201904 AS FIP
ON I.DlrZipClean = FIP.Zip2
LEFT JOIN (SELECT DISTINCT FIP,MSA
FROM decan1.zipfip_201904) AS FIP2
ON strip(I.DlrMSA) = strip(FIP2.FIP)
LEFT JOIN Sandbox.DFSELGeoAdjust AS ADJ
ON DATEPART(I.dte_entered) BETWEEN ADJ.StartDate AND ADJ.EndDate
AND I.DlrState = ADJ.DlrState
AND COALESCE(FIP.FIP,FIP2.FIP) = ADJ.FIP
LEFT JOIN FraudAccts AS F
ON I.src_sys_acct_key = F.src_sys_acct_key
LEFT JOIN SoldAccts AS S
ON I.src_sys_acct_key = S.src_sys_acct_key
LEFT JOIN SecureAccts AS S2
ON I.src_sys_acct_key = S2.src_sys_acct_key
/*This was added in Dec. 2018 for new drag rates*/
LEFT JOIN Sandbox.NetDragRates_2018Q3 AS ND
ON I.num_term BETWEEN ND.num_term_min AND ND.num_term_max
AND CASE WHEN I.ind_dlr_flat_fee EQ '' THEN 'N' ELSE I.ind_dlr_flat_fee END = ND.ind_dlr_flat_fee
AND CASE WHEN I.ind_dlr_flat_fee IN ('Y','X') THEN 100
WHEN I.ind_dlr_flat_fee EQ 'N' AND I.cde_dist_plan LT 70 THEN 100
ELSE I.cde_dist_plan END = ND.cde_dist_plan
LEFT JOIN Sandbox.DFS_PD AS PD1
ON round(I.ltv_PreBE,0.001) BETWEEN PD1.MetricMin and PD1.MetricMax
AND I.New_Used = PD1.NewUsed
AND datepart(I.dte_entered) BETWEEN PD1.StartDate AND PD1.EndDate
AND PD1.Metric = 'LTV'
LEFT JOIN Sandbox.DFS_PD AS PD2
on round(I.pti_PreBE,0.001) BETWEEN PD2.MetricMin and PD2.MetricMax
and I.New_Used = PD2.NewUsed
and datepart(I.dte_entered) BETWEEN PD2.StartDate AND PD2.EndDate
and PD2.Metric = 'PTI'
LEFT JOIN Sandbox.DFS_PD AS PD3
on I.num_term BETWEEN PD3.MetricMin and PD3.MetricMax
and I.New_Used = PD3.NewUsed
and datepart(I.dte_entered) BETWEEN PD3.StartDate AND PD3.EndDate
and PD3.Metric = 'Term'
left join Sandbox.DFS_EAD AS EAD
on round(I.ltv_PreBE,0.001) BETWEEN EAD.LTVMin and EAD.LTVMax
and round(I.pti_PreBE,0.001) BETWEEN EAD.PTIMin and EAD.PTIMax
and I.num_term BETWEEN EAD.TermMin and EAD.TermMax
and datepart(I.dte_entered) BETWEEN EAD.StartDate AND EAD.EndDate
left join Sandbox.DFS_Credit AS C
on I.app_id = C.id_appl
left join temp7d.dfs_ver_panel as v
on I.app_id = v.appl_id
;
QUIT;
Per #alexey-sigida, if indeed your Proc CONTENTS examination is correct
Check if either one or both tables (or table alias) has both columns
app_id
appl_id
If so, your join criteria would likely need to be changed from:
I.app_id = v.appl_id
to one of these:
I.app_id = v.app_id
I.appl_id = v.appl_id
First of all, I should state that this is a homework assignment, so while questions that give a direct answer will give me a good grade, I would prefer to know why something doesn't work, and a reason why/how I should fix it with your solution.
So here is the background for this function. I have a quarterback struct with the following information. There are ten games, which all are stored in the struct and its arrays:
struct QuarterBack{
string name;
int completions[kNumGames];
int attempts[kNumGames];
int yards[kNumGames];
int touchdowns[kNumGames];
int interceptions[kNumGames];
};
Now my goal for this problem is to use the information stored in these structs to compute the NFL Style passer ratings. For reference, wikipedia gives the following:
So here is the code I am using. It has some excessive parenthesis that I was trying to use to make sure my control was correct, but other than that I am stumped as to why I am not getting more correct answers. Below the code I will post an example file and output.
/**
* #brief printPasserRating prints the passer rating of all players
* #param players is the array holding all the players
*/
void printPasserRating(QuarterBack *players, int numPlayers){
for(int player = 0; player < numPlayers; player++){
double passerRating = 0;
int sumCompletions = 0, sumAttempts = 0, sumYards = 0,
sumTouchdowns = 0, sumInterceptions = 0;
for(int game = 0; game < kNumGames; game++){
sumCompletions += players[player].completions[game];
sumAttempts += players[player].attempts[game];
sumYards += players[player].yards[game];
sumTouchdowns += players[player].touchdowns[game];
sumInterceptions += players[player].interceptions[game];
}
double a = 0, b = 0, c = 0, d = 0;
double nums[4] = {a, b, c, d};
nums[0] = static_cast<double>((sumCompletions / sumAttempts) - 0.3) * 5;
nums[1] = static_cast<double>((sumYards / sumAttempts) - 3) * 0.25;
nums[2] = static_cast<double>(sumTouchdowns / sumAttempts) * 20;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions / sumAttempts) * 25);
for(int letter = 0; letter < 4; letter++){
nums[letter] = mm(nums[letter]);
}
passerRating = (nums[0] + nums[1] + nums[2] + nums[3]) / 0.06;
cout << players[player].name << "\t" << passerRating << endl;
}
showMenu(players, numPlayers);
}
Here is the example file. Ignore the 4, as it is for a separate part of the problem. Each row is a game, and it is listed as: completions, attempts, yards, touchdowns, then interceptions.
4
Peyton Manning
27 42 462 7 0
30 43 307 2 0
32 37 374 3 0
28 34 327 4 0
33 42 414 4 1
28 42 295 2 1
29 49 386 3 1
30 44 354 4 3
25 36 330 4 0
24 40 323 1 0
Tom Brady
29 52 288 2 1
19 39 185 1 0
25 36 225 2 1
20 31 316 2 0
18 38 197 0 1
25 43 269 1 1
22 46 228 0 1
13 22 116 1 1
23 33 432 4 0
29 40 296 1 1
Drew Brees
26 35 357 2 1
26 46 322 1 2
29 46 342 3 1
30 39 413 4 0
29 35 288 2 0
17 36 236 2 1
26 34 332 5 0
30 51 382 2 2
34 41 392 4 0
30 43 305 1 1
Eli Manning
24 35 360 1 2
25 46 340 2 3
26 44 350 3 1
34 35 460 1 2
25 36 240 2 3
16 34 250 3 1
24 35 360 1 0
35 56 340 2 2
36 44 350 3 0
34 45 360 1 1
And here is the output that the function is giving me:
Any help is much appreciated, and if you need more information to help me, feel free to comment and ask. Also, as this is a homework assignment, don't assume that I am just incompetent even if I make a silly mistake. I was told that Stack Overflow has no stupid questions, and I really hope that the community can live up to that.
This math is unlikely to do what you want:
nums[0] = static_cast<double>((sumCompletions / sumAttempts) - 0.3) * 5;
nums[1] = static_cast<double>((sumYards / sumAttempts) - 3) * 0.25;
nums[2] = static_cast<double>(sumTouchdowns / sumAttempts) * 20;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions / sumAttempts) * 25);
Where you've put the cast will cast the result of the division to be double after the division has been performed. But, the division itself will be an integer division.
You want something more like this:
nums[0] = (static_cast<double>(sumCompletions) / sumAttempts - 0.3) * 5.0;
nums[1] = (static_cast<double>(sumYards) / sumAttempts - 3) * 0.25;
nums[2] = (static_cast<double>(sumTouchdowns) / sumAttempts) * 20.0;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions) / sumAttempts) * 25.0;
By casting one of the terms in the divide to double, the division itself upgrades to double.
Alternately, you could just declare all of these variables to be double and avoid the casts entirely. That would make the code much easier to follow. Or, just make sumAttempts into a double, as it is common to all of the four divides.
I think the issue is in code like this:
static_cast<double>((sumCompletions / sumAttempts) - 0.3)
Here, sumCompletions and sumAttempts are ints. While you're trying to do a cast to a double to avoid integer division, the cast is on the complete value of the expression rather than on the numerator or denominator. This means that the division performed is integer division, which then has 0.3 subtracted and the result, which is already a double, is then cast to a double.
To fix this, cast the numerator or denominator, not the quotient itself:
static_cast<double>(sumCompletions) / sumAttempts - 0.3
Hope this helps!
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am currently trying to understand how the following code (http://pastebin.com/zTHUrmyx) works, my approach is currently compiling the software in debug and using gdb to step through the code.
However, I'm running into the problem that 'step' does not always tell me what is going on. Particularly unclear to me is the EXECUTE {...} which I cannot step into.
How do I go about learning what the code is doing?
1 /*
2 Copyright 2008 Brain Research Institute, Melbourne, Australia
3
4 Written by J-Donald Tournier, 27/06/08.
5
6 This file is part of MRtrix.
7
8 MRtrix is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 MRtrix is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with MRtrix. If not, see <http://www.gnu.org/licenses/>.
20
21
22 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
23 * fix -prs option handling
24 * remove MR::DICOM_DW_gradients_PRS flag
25
26 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
27 * add -layout option to manipulate data ordering within the image file
28
29 14-02-2010 J-Donald Tournier <d.tournier#brain.org.au>
30 * fix -coord option so that the "end" keyword can be used
31
32
33 */
34
35 #include "app.h"
36 #include "image/position.h"
37 #include "image/axis.h"
38 #include "math/linalg.h"
39
40 using namespace std;
41 using namespace MR;
42
43 SET_VERSION_DEFAULT;
44
45 DESCRIPTION = {
46 "perform conversion between different file types and optionally extract a subset of the input image.",
47 "If used correctly, this program can be a very useful workhorse. In addition to converting images between different formats, it can be used to extract specific studies from a data set, extract a specific region of interest, flip the images, or to scale the intensity of the images.",
48 NULL
49 };
50
51 ARGUMENTS = {
52 Argument ("input", "input image", "the input image.").type_image_in (),
53 Argument ("ouput", "output image", "the output image.").type_image_out (),
54 Argument::End
55 };
56
57
58 const gchar* type_choices[] = { "REAL", "IMAG", "MAG", "PHASE", "COMPLEX", NULL };
59 const gchar* data_type_choices[] = { "FLOAT32", "FLOAT32LE", "FLOAT32BE", "FLOAT64", "FLOAT64LE", "FLOAT64BE",
60 "INT32", "UINT32", "INT32LE", "UINT32LE", "INT32BE", "UINT32BE",
61 "INT16", "UINT16", "INT16LE", "UINT16LE", "INT16BE", "UINT16BE",
62 "CFLOAT32", "CFLOAT32LE", "CFLOAT32BE", "CFLOAT64", "CFLOAT64LE", "CFLOAT64BE",
63 "INT8", "UINT8", "BIT", NULL };
64
65 OPTIONS = {
66 Option ("coord", "select coordinates", "extract data only at the coordinates specified.", false, true)
67 .append (Argument ("axis", "axis", "the axis of interest").type_integer (0, INT_MAX, 0))
68 .append (Argument ("coord", "coordinates", "the coordinates of interest").type_sequence_int()),
69
70 Option ("vox", "voxel size", "change the voxel dimensions.")
71 .append (Argument ("sizes", "new dimensions", "A comma-separated list of values. Only those values specified will be changed. For example: 1,,3.5 will change the voxel size along the x & z axes, and leave the y-axis voxel size unchanged.")
72 .type_sequence_float ()),
73
74 Option ("datatype", "data type", "specify output image data type.")
75 .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (data_type_choices)),
76
77 Option ("scale", "scaling factor", "apply scaling to the intensity values.")
78 .append (Argument ("factor", "factor", "the factor by which to multiply the intensities.").type_float (NAN, NAN, 1.0)),
79
80 Option ("offset", "offset", "apply offset to the intensity values.")
81 .append (Argument ("bias", "bias", "the value of the offset.").type_float (NAN, NAN, 0.0)),
82
83 Option ("zero", "replace NaN by zero", "replace all NaN values with zero."),
84
85 Option ("output", "output type", "specify type of output")
86 .append (Argument ("type", "type", "type of output.")
87 .type_choice (type_choices)),
88
89 Option ("layout", "data layout", "specify the layout of the data in memory. The actual layout produced will depend on whether the output image format can support it.")
90 .append (Argument ("spec", "specifier", "the data layout specifier.").type_string ()),
91
92 Option ("prs", "DW gradient specified as PRS", "assume that the DW gradients are specified in the PRS frame (Siemens DICOM only)."),
93
94 Option::End
95 };
96
97
98
99 inline bool next (Image::Position& ref, Image::Position& other, const std::vector<int>* pos)
100 {
101 int axis = 0;
102 do {
103 ref.inc (axis);
104 if (ref[axis] < ref.dim(axis)) {
105 other.set (axis, pos[axis][ref[axis]]);
106 return (true);
107 }
108 ref.set (axis, 0);
109 other.set (axis, pos[axis][0]);
110 axis++;
111 } while (axis < ref.ndim());
112 return (false);
113 }
114
115
116
117
118
119 EXECUTE {
120 std::vector<OptBase> opt = get_options (1); // vox
121 std::vector<float> vox;
122 if (opt.size())
123 vox = parse_floats (opt[0][0].get_string());
124
125
126 opt = get_options (3); // scale
127 float scale = 1.0;
128 if (opt.size()) scale = opt[0][0].get_float();
129
130 opt = get_options (4); // offset
131 float offset = 0.0;
132 if (opt.size()) offset = opt[0][0].get_float();
133
134 opt = get_options (5); // zero
135 bool replace_NaN = opt.size();
136
137 opt = get_options (6); // output
138 Image::OutputType output_type = Image::Default;
139 if (opt.size()) {
140 switch (opt[0][0].get_int()) {
141 case 0: output_type = Image::Real; break;
142 case 1: output_type = Image::Imaginary; break;
143 case 2: output_type = Image::Magnitude; break;
144 case 3: output_type = Image::Phase; break;
145 case 4: output_type = Image::RealImag; break;
146 }
147 }
148
149
150
151
152 Image::Object &in_obj (*argument[0].get_image());
153
154 Image::Header header (in_obj);
155
156 if (output_type == 0) {
157 if (in_obj.is_complex()) output_type = Image::RealImag;
158 else output_type = Image::Default;
159 }
160
161 if (output_type == Image::RealImag) header.data_type = DataType::CFloat32;
162 else if (output_type == Image::Phase) header.data_type = DataType::Float32;
163 else header.data_type.unset_flag (DataType::ComplexNumber);
164
165
166 opt = get_options (2); // datatype
167 if (opt.size()) header.data_type.parse (data_type_choices[opt[0][0].get_int()]);
168
169 for (guint n = 0; n < vox.size(); n++)
170 if (isfinite (vox[n])) header.axes.vox[n] = vox[n];
171
172 opt = get_options (7); // layout
173 if (opt.size()) {
174 std::vector<Image::Axis> ax = parse_axes_specifier (header.axes, opt[0][0].get_string());
175 if (ax.size() != (guint) header.axes.ndim())
176 throw Exception (String("specified layout \"") + opt[0][0].get_string() + "\" does not match image dimensions");
177
178 for (guint i = 0; i < ax.size(); i++) {
179 header.axes.axis[i] = ax[i].axis;
180 header.axes.forward[i] = ax[i].forward;
181 }
182 }
183
184
185 opt = get_options (8); // prs
186 if (opt.size() && header.DW_scheme.rows() && header.DW_scheme.columns()) {
187 for (guint row = 0; row < header.DW_scheme.rows(); row++) {
188 double tmp = header.DW_scheme(row, 0);
189 header.DW_scheme(row, 0) = header.DW_scheme(row, 1);
190 header.DW_scheme(row, 1) = tmp;
191 header.DW_scheme(row, 2) = -header.DW_scheme(row, 2);
192 }
193 }
194
195 std::vector<int> pos[in_obj.ndim()];
196
197 opt = get_options (0); // coord
198 for (guint n = 0; n < opt.size(); n++) {
199 int axis = opt[n][0].get_int();
200 if (pos[axis].size()) throw Exception ("\"coord\" option specified twice for axis " + str (axis));
201 pos[axis] = parse_ints (opt[n][1].get_string(), header.dim(axis)-1);
202 header.axes.dim[axis] = pos[axis].size();
203 }
204
205 for (int n = 0; n < in_obj.ndim(); n++) {
206 if (pos[n].empty()) {
207 pos[n].resize (in_obj.dim(n));
208 for (guint i = 0; i < pos[n].size(); i++) pos[n][i] = i;
209 }
210 }
211
212
213 in_obj.apply_scaling (scale, offset);
214
215
216
217
218
219
220 Image::Position in (in_obj);
221 Image::Position out (*argument[1].get_image (header));
222
223 for (int n = 0; n < in.ndim(); n++) in.set (n, pos[n][0]);
224
225 ProgressBar::init (out.voxel_count(), "copying data...");
226
227 do {
228
229 float re, im = 0.0;
230 in.get (output_type, re, im);
231 if (replace_NaN) if (gsl_isnan (re)) re = 0.0;
232 out.re (re);
233
234 if (output_type == Image::RealImag) {
235 if (replace_NaN) if (gsl_isnan (im)) im = 0.0;
236 out.im (im);
237 }
238
239 ProgressBar::inc();
240 } while (next (out, in, pos));
241
242 ProgressBar::done();
243 }
As was noted in the comments, EXECUTE seems to be a macro, apparent from the context a function header (and maybe a bit more, e.g. some global variables and functions), so the part in curly braces is the function body.
To get to the definition of EXECUTE, you will have to examine the headers.
However, if you can reach some part of the code during debugging, you could insert a string or char[] at that point, giving it the stringified version of EXECUTE, so you get whatever the preprocessor will emit for EXECUTE at that position in the code.
#define STR(x) #x
#define STRINGIFY(x) STR(x)
char c[] = STRINGIFY(EXECUTE);
the two macros are a known little macro trick to get the content of any macro as a string literal. Try it out and inspect the char array in your debugger to get the content of execute.
My wild guess here: EXECUTE is the main function or a replacement for it, the OPTIONS and ARGUMENTS describe what arguments the program expects and what command line options you can pass to it. Those macros and some of the used functions and variables (get_options, argument) are part of a little framework that should facilitate the usage, evaluation and user information about command line options.